【設計モードシリーズ5】プロトタイプモードと浅いクローンと深いクローンの違いを深く分析する


JAva設計モードのプロトタイプモード
  • 設計モードシリーズ一覧
  • プロトタイプパターン
  • とは
  • プロトタイプパターン例1
  • 1.標準的なプロトタイプモードは、まずプロトタイプインタフェース
  • を作成する必要がある.
  • 2.オブジェクト実装プロトタイプインタフェース
  • を作成する
  • 3.試験クラス
  • の作成
  • プロトタイプパターン例2
  • 1.Cloneableインタフェース
  • を実装するプロトタイプオブジェクトを作成する
  • .テストクラス
  • の作成
  • 3.PrototypeBクラスを書き換え、深いクローン
  • を実現する
  • 4.深いクローンによる問題
  • プロトタイプモード適用シーン
  • プロトタイプモードの利点
  • プロトタイプモード欠点
  • まとめ
  • デザインモードシリーズ一覧
    デザインモード
    航空券
    三大工場モデル
    搭乗ゲート
    ポリシー・モード
    搭乗ゲート
    委任モード
    搭乗ゲート
    テンプレートメソッドモード
    搭乗ゲート
    オブザーバモード
    搭乗ゲート
    単一モード
    搭乗ゲート
    プロトタイプモード
    搭乗ゲート
    プロキシモード
    搭乗ゲート
    デコレーションモード
    搭乗ゲート
    アダプタモード
    搭乗ゲート
    コンストラクタモード
    搭乗ゲート
    責任チェーンモード
    搭乗ゲート
    ユーティリティーモード
    搭乗ゲート
    コンビネーションモード
    搭乗ゲート
    ファセットモード
    搭乗ゲート
    ブリッジモード
    搭乗ゲート
    仲介者モード
    搭乗ゲート
    反復モード
    搭乗ゲート
    ステータスモード
    搭乗ゲート
    インタプリタモード
    搭乗ゲート
    メモモード
    搭乗ゲート
    コマンドモード
    搭乗ゲート
    ビジターモード
    搭乗ゲート
    ソフトウェア設計7大原則と設計モデルの総括
    搭乗ゲート
    プロトタイプモードとは
    プロトタイプ・モード(Prototype Pattern)とは、プロトタイプ・インスタンスが作成オブジェクトの種類を指定し、これらのプロトタイプをコピーして新しいオブジェクトを作成することで、呼び出し元は作成の詳細を知る必要がなく、コンストラクション関数を呼び出さず、プロトタイプ・モードは作成モードに属します.
    プロトタイプパターン例1
    1.標準的なプロトタイプモードでは、プロトタイプインタフェースを作成する必要があります.
    package com.zwx.design.pattern.prototype;
    
    public interface IPrototype {
         
        IPrototype clone();
    }
    

    2.オブジェクト実装プロトタイプインタフェースを作成する
    package com.zwx.design.pattern.prototype.impl;
    
    import com.zwx.design.pattern.prototype.IPrototype;
    import java.util.List;
    
    public class PrototypeImplA implements IPrototype{
         
        private String name;
    
        private int age;
    
        private List<String> phoneList;
    
        public String getName() {
         
            return name;
        }
    
        public void setName(String name) {
         
            this.name = name;
        }
    
        public int getAge() {
         
            return age;
        }
    
        public void setAge(int age) {
         
            this.age = age;
        }
        public List<String> getPhoneList() {
         
            return phoneList;
        }
    
        public void setPhoneList(List<String> phoneList) {
         
            this.phoneList = phoneList;
        }
    
        @Override
        public IPrototype clone() {
         
            PrototypeImplA prototypeImplA = new PrototypeImplA();
            prototypeImplA.setAge(this.age);
            prototypeImplA.setName(this.name);
            prototypeImplA.setPhoneList(this.phoneList);
            return prototypeImplA;
        }
    }
    

    PrototypeImplaAはインタフェースIPrototypeを実現し、cloneメソッドを実現し、新しいオブジェクトを返します.
    3.テストクラスの作成
    package com.zwx.design.pattern.prototype;
    
    import com.zwx.design.pattern.prototype.impl.PrototypeImplA;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ProtoTypeTest {
         
        public static void main(String[] args) throws Exception {
         
            PrototypeImplA prototypeImplA = new PrototypeImplA();
            prototypeImplA.setAge(18);
            prototypeImplA.setName("  ");
            List<String> phoneList = new ArrayList<>();
            phoneList.add("88888888");
            phoneList.add("77777777");
            prototypeImplA.setPhoneList(phoneList);
    
            PrototypeImplA cloneProtoType = (PrototypeImplA) prototypeImplA.clone();
            System.out.println(prototypeImplA.getPhoneList() == cloneProtoType.getPhoneList());//true
        }
    }
    

    最後にtrueが出力されます.これは、このクローン方式が浅いクローンであるためです.オブジェクトに参照オブジェクトがある場合、クローンされたオブジェクトは元のオブジェクトを指します.2つの独立したオブジェクトをコピーする必要がある場合は、深いクローンを使用する必要があります.次の例2では、2つのクローン方式を比較します.
    プロトタイプパターン例2
    1.Cloneableインタフェースを実装するプロトタイプオブジェクトを作成する
    package com.zwx.design.pattern.prototype.impl;
    
    import java.io.*;
    import java.util.List;
    
    public class PrototypeB implements Cloneable {
         
        private String name;
    
        private int age;
    
        private List<String> phoneList;
    
        public String getName() {
         
            return name;
        }
    
        public void setName(String name) {
         
            this.name = name;
        }
    
        public int getAge() {
         
            return age;
        }
    
        public void setAge(int age) {
         
            this.age = age;
        }
    
        public List<String> getPhoneList() {
         
            return phoneList;
        }
    
        public void setPhoneList(List<String> phoneList) {
         
            this.phoneList = phoneList;
        }
        public Object clone() throws CloneNotSupportedException {
         
            return super.clone();
        }
    }
    

    Objectクラスのデフォルトにはclone()メソッド、protectedレベル、および浅いクローンがあります.デフォルトのclone()メソッドを使用する必要がある場合は、Cloneableインタフェース(Cloneableはタグインタフェースであり、Serializableなどのインタフェースも似ています)を実装する必要があります.そうしないと、例外CloneNotSupportedExceptionが放出されます.
    2.テストクラスの作成
    package com.zwx.design.pattern.prototype;
    
    import com.zwx.design.pattern.prototype.impl.PrototypeB;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ProtoTypeTest2 {
         
        public static void main(String[] args) throws CloneNotSupportedException {
         
            PrototypeB prototypeImplB = new PrototypeB();
            prototypeImplB.setAge(18);
            prototypeImplB.setName("  ");
            List<String> phoneList = new ArrayList<>();
            phoneList.add("88888888");
            phoneList.add("77777777");
            prototypeImplB.setPhoneList(phoneList);
    
            PrototypeB cloneProtoTypeB = (PrototypeB)prototypeImplB.clone();
            System.out.println(prototypeImplB.getPhoneList() == cloneProtoTypeB.getPhoneList());//true
        }
    }
    

    このとき出力される結果はtrueです.上ではObjectが持参したclone()メソッドを使用しているので、デフォルトは浅いクローンですが、どのようにして深いクローンを実現しますか?次にPrototypeBクラスを書き換えます.
    3.PrototypeBクラスを書き換え、深いクローンを実現
    package com.zwx.design.pattern.prototype.impl;
    
    import java.io.*;
    import java.util.List;
    
    public class PrototypeB implements Cloneable, Serializable {
         
        private String name;
    
        private int age;
    
        private List<String> phoneList;
    
        public String getName() {
         
            return name;
        }
    
        public void setName(String name) throws CloneNotSupportedException{
         
            this.name = name;
        }
    
        public int getAge() {
         
            return age;
        }
    
        public void setAge(int age) {
         
            this.age = age;
        }
    
        public List<String> getPhoneList() {
         
            return phoneList;
        }
    
        public void setPhoneList(List<String> phoneList) {
         
            this.phoneList = phoneList;
        }
        public Object clone() throws CloneNotSupportedException {
         
    //        return super.clone();
            return this.deepClone();
        }
    
        public PrototypeB deepClone(){
         
            try {
         
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(bos);
                oos.writeObject(this);
    
                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bis);
    
                PrototypeB clone = (PrototypeB)ois.readObject();
                return clone;
            }catch (Exception e){
         
                return null;
            }
        }
    }
    

    Serializableインタフェースを複数実装し、clone()メソッドでカスタムの深クローンメソッドdeepClone()を返します.このときテストクラスを実行し、falseを返します.
    4.深いクローンによる問題
    深いクローンは単一のオブジェクトを破壊するので、単一のオブジェクトであれば、2つの方法で破壊を防止することができます:1、Cloneableインタフェースを実現しないで、このクラスがクローン2をサポートしないで、clone()メソッドを書き換えて、そして単一のオブジェクトを返します
    プロトタイプモード適用シーン
    1、クラス初期化消費リソースが多い場合2、1つのオブジェクトを初期化する際に非常に煩雑なプロセスが必要な場合3、コンストラクション関数が複雑な場合4、サイクル中に大量のオブジェクトを生産する場合、可読性が低下する場合
    プロトタイプモードの利点
    1.オブジェクトの作成が複雑な場合、プロトタイプオブジェクトの使用は通常より効率的である
    プロトタイプモードの欠点
    1、オブジェクトごとにクローンまたはコピー可能な方法を配備する必要がある2、複雑なオブジェクトをクローンしたり、クローンしたオブジェクトを複雑に改造したりする場合、リスクをもたらしやすく、深いクローン、浅いクローンは適切に運用しなければならない
    まとめ
    プロトタイプモードとは,オブジェクトを迅速に構築する方法をまとめ,単純な工場でgetter,setterをある方法にカプセル化することで,迅速なレプリケーションを実現する方法である.プロトタイプモードはいったい浅いクローンを採用すべきか、それとも深いクローンを採用すべきか.これは実際のビジネスシーンに基づいて具体的に分析する必要がありますが、浅いクローンがニーズを満たす場合でも、Cloneableインタフェースを実現し、clone()メソッドをpublicと定義し、super.clone()を呼び出してクローンオブジェクトに戻る必要があります.