デザインパターン(14) - プロトタイプパターン(プロトタイプ)

概念定義

試作品の例としては、オブジェクトの種類を指定するには、このプロトタイプをコピーして新しいオブジェクトを作成するために作成されます。プロトタイププロトタイプオブジェクトモデル作成方法の任意の詳細を知らなくても、複製(コピー)オブジェクトの同一それ複数のを可能にします。

シナリオ

  • オブジェクトの作成は、より複雑で作成し、頻繁に必要とします
  • 例えば、従来例に係る新たなインスタンスを生成することが望ましいです。
    • オブジェクトの広い範囲がクラスに統合することができない場合には
    • のインスタンスによって生成されたクラス名を指定することは困難であるとき
    • デカップリングの所望生成されたフレームの例

実用的なアプリケーションでは、プロトタイプモデルはめったにだけでは発生しません。多くの場合、他のモードと混合。

プロトタイプの実装

すべてのクラスは、Javaから継承java.lang.Objectし、Objectクラスは、クローンオブジェクトにクローン()メソッドを提供します。したがって、Javaクラスその実装インターフェイスと書き換えCloneableをクローン()メソッドは、プロトタイプパターンを実現することができます

原型パターン例コード次のように

// 原型类(也可定义为interface Prototype extends Cloneable)
abstract class Prototype implements Cloneable {
    private String name;
    public void setName(String name) {this.name = name;}
    public String getName() {return this.name;}

    public abstract void doSomething();

    @Override
    public Object clone() { // clone()方法用public修饰
        Object object = null;
        try {
            object = super.clone(); // 调用父类clone()方法
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return object;
    }
}

// 具体实现类(继承自Prototype类自动具有克隆功能)
class ConcretePrototype extends Prototype{
    public ConcretePrototype() { setName("ConcretePrototype"); }

    @Override
    public void doSomething() { System.out.println("I'll clone myself!"); }
}

public class PrototypeDemo {
    public static void main(String[] args) {
        ConcretePrototype cp = new ConcretePrototype();
        cp.doSomething();

        for(int i=0; i< 5; i++){
            ConcretePrototype cloned = (ConcretePrototype)cp.clone();
            System.out.println("I'm cloned by " + cloned.getName());
        }
    }
}

次の出力を実行した後:

I'll clone myself!
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype

長所と短所モード

利点は、以下のプロトタイプパターン:

  • ランタイムクライアントを作成するために、動的なオブジェクトのためのクライアントの要件に応じてコードを維持し、拡大しやすく、オブジェクトの作成の詳細を知る必要はありません。
  • より複雑な作成するオブジェクトを作成するか、または同様の多数のオブジェクトを繰り返したときに、オブジェクトを簡略化を作成し、パフォーマンス新しいオブジェクトよりも高い(自動的にすべての新しいコンストラクタチェーンを呼び出しますが、任意のクローンクラスのコンストラクタメソッドを呼び出さない)直接。
  • 試作工場モードと同様のパターンが、明確でシンプルな何の階層関係抽象的な工場モデル植物や植物固有のコード構造はありません。

次のような欠点があります:

  • 必要()各クラスが実装Cloneableインタフェースのために変更されなければならないとは逆に、そのソースの既存のクラスを変更することによって、場合cloneメソッドをオーバーライド「開閉の原理」
  • シングルトンと工場出荷時のモデルは、プロトタイプモデルが競合している、混在しないようにしてください。
  • 複雑なコードを書くための深いコピー(深いクローン)の必要性を実装する場合。

注意事項

アレイ、コンテナオブジェクト、オブジェクト参照などをコピーせずに、オブジェクトの基本的なデータタイプをコピーするclone()メソッド。深いコピーを実現するには、別のコピーのようなアレイモード、コンテナオブジェクト、参照オブジェクトのプロトタイプを作成しなければなりません
他の目的は、例えば、オブジェクトのディープコピー、オブジェクトがCloneableインタフェースとオーバーライドクローン()メソッドを実装する必要があり、参照クローン()メソッド内のオブジェクトは、クローンです。同様に、参照されるオブジェクトは、同じプロセスを実行します。
注、ブール、バイト、文字、クラス 、ダブル、フロート、整数、ロング、ショート、文字列、および例外サブクラスのほとんどは不変クラスであり、深いコピーにオブジェクトを実装する必要はありません。また、Javaコンテナクラスの大部分は、クローニング機能を実現してきました。

対照的に、clone()メソッドは、ディープコピーの配列により適しています。しかし、次の2点に注意してください。

(1)このようなことにより、一次元アレイの基本的なタイプの(int[])data.clone()クローニングの形、「二次元配列」の基本的なタイプウェイKelongによって必要とされる(例えば、int型として実際、[]一次元アレイです)。例えば:

public static int[][] twoDimensionArrayClone (int[][] tdArray){
    int[][] copy = tdArray.clone();
    for (int i = 0; i < tdArray.length; i++) {
        copy[i] = tdArray[i].clone();
    }
    return copy;
}

通常のJavaオブジェクトに配列の要素だけでなく、クローンクローニングされた配列は、アレイに含まれる(2)。次の例は、詳細に浅いオブジェクトの配列のディープコピー対さまざまな方法を示しています。

class Person implements Cloneable {
    public String name;
    public Person(String name) {this.name = name;}

    @Override
    public Object clone() {
        Object object = null;
        try {
            object = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return object;
    }
}

public class ArrayPrototype {
    public static void main(String[] args) {
		Person[] origin = new Person[] { new Person("Mike"), new Person("Jack"), new Person("Jason") };
		Person[] copyOf = Arrays.copyOf(origin, origin.length);
		// 浅拷贝(内部调用System.arraycopy,返回新数组)
		Person[] arrayCopy = new Person[origin.length];
		// 浅拷贝(可拷贝部分数组)
		System.arraycopy(origin, 0, arrayCopy, 0, origin.length);
		Person[] clonedCopy = origin.clone();
		// 浅拷贝
		System.out.println("origin=copyOf=arrayCopy=clonedCopy="
				+ (origin[0] == copyOf[0] && copyOf[1] == arrayCopy[1] && arrayCopy[2] == clonedCopy[2]));
		clonedCopy[0].name = "Lily";
		System.out.println("Shallow Person[0]: " + origin[0].name + " -> " + clonedCopy[0].name);

		Person[] deepCopy = new Person[origin.length];
		// 深拷贝
		for (int i = 0; i < origin.length; i++) {
			deepCopy[i] = (Person) origin[i].clone();
		}
		deepCopy[1].name = "Lily";
		System.out.println("Deep Person[1]: " + origin[1].name + " -> " + clonedCopy[1].name);
		Person[] deepCopy2 = Arrays.stream(origin).map(Person::clone).toArray(Person[]::new);
		// 深拷贝
		deepCopy2[2].name = "Lucy";
		System.out.println("Deep Person[2]: " + origin[2].name + " -> " + deepCopy2[2].name);
	}
}

業界の慣行

  • アクション・オブジェクト(Struts2の)
  • 作成されたBeanインスタンス(春)のプロトタイプ
公開された295元の記事 ウォン称賛37 ビュー30000 +

おすすめ

転載: blog.csdn.net/tianshan2010/article/details/104722260