一連の記事
23のデザインパターン-デザインパターンの目的と
23のデザインパターンに従う7つの原則-シングルトンモード[空腹、怠惰、ダブルチェック、静的内部クラス、列挙]
23のデザインパターン-ファクトリモード[シンプルファクトリ、ファクトリメソッド、抽象ファクトリ]
23のデザインモード-プロトタイプモード[クローンシープ、浅いコピー、深いコピー]
記事のディレクトリ
3.プロトタイプモード
3.1。伝統的な方法で羊のクローンを作成する
現在、トムという名前の2歳の白い羊がいます。このプログラムを使用して、トムとまったく同じ属性を持つ10頭の羊を作成します。
元のアイデア:直接新しい10回
package design_partten.prototype.type1;
public class Sheep {
private String name;
private int age;
private String color;
//省略构造方法、set、get
}
public class Client {
public static void main(String[] args) {
Sheep sheep1 = new Sheep("Tom", 3, "白色");
Sheep sheep2 = new Sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
Sheep sheep3 = new Sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
Sheep sheep4 = new Sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
Sheep sheep5 = new Sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
//...
}
}
長所と短所:
-
理解が深まり、シンプルで操作が簡単
-
新しいオブジェクトを作成するときは、常に元のオブジェクトのプロパティを再取得する必要があります。作成されたオブジェクトがより複雑な場合、効率は非常に低くなります。
-
オブジェクトは常に再初期化する必要があり、オブジェクトの実行時状態を動的に取得することはできません(たとえば、新しい属性が元のクラスに追加された場合、新しいクラスのコードを変更する必要があります)。これは十分な柔軟性がありません。 。
-
改善のアイデア:
JavaのObjectクラスは、すべてのクラスのルートクラスであり、Javaオブジェクトのコピーを作成できるclone()メソッドを提供します。Cloneableインターフェースを実装する必要があります。これは、このクラスをコピーでき、コピーする機能があることを意味します。これがプロトタイプモデルにつながります。
3.2、プロトタイプモードで羊のクローンを作成する
-
プロトタイプモード(プロトタイプ):プロトタイプインスタンスを使用して、作成するオブジェクトのタイプを指定し、これらのプロトタイプをコピーして新しいオブジェクトを作成します。
-
仕組み:プロトタイプオブジェクトを作成するオブジェクトに渡します。作成するオブジェクトは、作成を実装するために自分自身をコピーするように要求します。つまり、object.clone()
羊
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
private String address="内蒙古";
//省略构造方法、set、get、toString
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
}catch (Exception e){
e.getStackTrace();
}
return sheep;
}
}
テスト
public class Client {
public static void main(String[] args) {
Sheep sheep1 = new Sheep("Tom", 3, "白色");
Sheep sheep2 = (Sheep)sheep1.clone();
Sheep sheep3 = (Sheep)sheep1.clone();
//...
System.out.println(sheep2);
}
}
結果:
結論:プロトタイプモードで羊のクローンを作成することは、従来の方法よりも柔軟性があり、属性の値を直接クローンします。
3.3。Springのプロトタイプパターンのソースコード分析
依存性注入では、プロトタイプモードを選択できます。
debugと入力して、Beanを取得する方法を確認してください。
ここに豆工場がありますので、ぜひご覧ください。
最も重要なdoGetBeanもあります。doGetBeanに入ると、内部で設定したプロトタイプモードが表示されます。
彼はそれがシングルトンであるかどうか、それがプロトタイプであるかどうかを判断します
3.4、ディープコピー
クローン羊のメンバー変数はすべて基本タイプです。メンバーにオブジェクトがある場合はどうなりますか?
メンバー変数がオブジェクトの場合、以前の方法でコピーされた場合、新しいメンバーオブジェクトは作成されません。たとえば、次のようになります。
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
private String address="内蒙古";
private Sheep friend;
//....
}
public class Client {
public static void main(String[] args) {
Sheep sheep1 = new Sheep("Tom", 3, "白色");
sheep1.setFriend(new Sheep("Bob", 2, "黑色"));
Sheep sheep2 = (Sheep) sheep1.clone();
Sheep sheep3 = (Sheep) sheep1.clone();
//...
System.out.println(sheep1.getFriend().hashCode());
System.out.println(sheep2.getFriend().hashCode());
System.out.println(sheep3.getFriend().hashCode());
}
}
3匹の羊の友達はすべて同じオブジェクトであり、それらの参照アドレスは同じです。これはシャローコピーと呼ばれます(clone()のデフォルトの使用はシャローコピーです)。この場合、1つのクローンの友達を変更すると他のクローンに影響します。クローン。。対照的に、コピーすると、そのオブジェクトタイプのメンバーもコピーされます。これはディープコピーと呼ばれます。
ディープコピーの基本的な紹介:
- オブジェクトのすべての基本データ型のメンバー変数値をコピーします
- 参照データ型のすべてのメンバー変数のストレージスペースを申請し、参照データ型の各メンバー変数によって参照されるオブジェクトをコピーします。つまり、オブジェクトのディープコピーは、すべてのメンバー変数をコピーします。
- ディープコピーの実装:1。Re-clone()メソッド; 2。オブジェクトのシリアル化を通じて実現します。
メソッド1:Re-clone()メソッド(私は怠惰すぎてセットを記述してここに到達できません。変数をパブリックとして宣言するだけです)
package design_partten.prototype.type1.improve;
class Bird implements Cloneable{
public String name;
public Bird(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Sheep implements Cloneable {
public String name;
public int age;
public String color;
public Bird friend;
public Sheep(String name, int age, String color, Bird friend) {
this.name = name;
this.age = age;
this.color = color;
this.friend = friend;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//1. 先拷贝基本数据类型的成员变量
Sheep sheep = (Sheep) super.clone();
//2. 拷贝引用类型的成员变量(即对引用类型成员再进行一次拷贝,然后赋值给刚刚拷贝的克隆羊)
Bird friend = (Bird) this.friend.clone();
sheep.friend = friend;
return sheep;
}
}
テスト:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep1 = new Sheep("Tom", 3, "白色", new Bird("鸟"));
Sheep sheep2 = (Sheep) sheep1.clone();
Sheep sheep3 = (Sheep) sheep1.clone();
//...
System.out.println(sheep1.friend.hashCode());
System.out.println(sheep2.friend.hashCode());
System.out.println(sheep3.friend.hashCode());
}
}
結果:
評価:ディープコピーはre-clone()メソッドによって実現されます。見た目はシンプルでコードが少ないですが、参照型のメンバー変数が1つしかないためです。多くのメンバー変数が参照型の場合、各変数は書く必要があります。推奨されません。
方法2:オブジェクトのシリアル化を通じて実現する(推奨)
//在Sheep类添加该方法,且Sheep和Bird实现Serialized接口
public Object deepClone(){
//创建字节数组输出流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);//当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
Sheep sheep = (Sheep)ois.readObject();
return sheep;
}catch (Exception e){
e.getStackTrace();
return null;
}finally {
//关闭流
try {
ois.close();
bis.close();
oos.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.5まとめ
- 新しいオブジェクトの作成がより複雑な場合は、プロトタイプモードを使用して、オブジェクトの作成プロセスを簡素化すると同時に、効率を向上させることができます。
- オブジェクトを再初期化する必要はありませんが、オブジェクトの実行時状態を動的に取得します。つまり、オブジェクトのプロパティが後で変更された場合、プロパティ変更後のオブジェクトは、元のオブジェクトではなく、クローン作成によって取得されます。
- 元のオブジェクトが変更された場合(属性の増加または減少)、コードを変更せずに、他の複製されたオブジェクトもそれに応じて変更されます。
- 短所:クローンメソッドを増やす必要があります。これは、新しいクラスでは問題ありませんが、以前に作成されたクラスでは、OCPの原則に違反します。