Javaデザインパターン-プロトタイプパターン

1はじめに

一部のシステムでは、同じまたは類似のオブジェクトの作成に多くの問題があります。従来のコンストラクターを使用してオブジェクトを作成すると、より複雑で時間とリソースを消費します。プロトタイプモードを使用してオブジェクトを生成するのはモンキーキングがモンキーヘアを抜くのと同じように、非常に効率的です。一撃でたくさんのモンキーキングに変わるのと同じくらい簡単です。

2.プロトタイプモデルの定義と特徴

プロトタイプ(プロトタイプ)モードの定義は次のとおりです。作成済みのインスタンスをプロトタイプとして使用し、プロトタイプオブジェクトをコピーして、プロトタイプと同じまたは類似した新しいオブジェクトを作成します。ここで、プロトタイプインスタンスは、作成するオブジェクトの種類を指定します。この方法でオブジェクトを作成することは非常に効率的であり、オブジェクト作成の詳細をまったく知る必要はありません。たとえば、Windowsオペレーティングシステムのインストールには通常時間がかかり、コピーははるかに高速です。

プロトタイプモードの利点:

  • Java独自のプロトタイプモードは、メモリのバイナリストリームのコピーに基づいています。これは、オブジェクトを直接新しいものにするよりもパフォーマンスが優れています。
  • ディープクローニングメソッドを使用してオブジェクトの状態を保存し、プロトタイプモードを使用してオブジェクトをコピーし、その状態を保存できます。これにより、必要に応じて使用するオブジェクトを作成するプロセスが簡素化されます(たとえば、特定のオブジェクトに復元するため)。履歴状態)元に戻す操作の実現を支援します。

プロトタイプモードのデメリット:

  • クラスごとにクローンメソッドを構成する必要があります
  • cloneメソッドはクラス内にあります。既存のクラスを変換する場合、コードを変更する必要があります。これは、開始と終了の原則に違反します。
  • ディープクローニングを実装する場合、より複雑なコードを記述する必要があります。オブジェクト間にネストされた参照が複数ある場合、ディープクローニングを実現するには、オブジェクトの各レイヤーに対応するクラスがディープクローニングをサポートする必要があり、実装がより面倒になります。 。したがって、ディープクローニングとシャロークローニングを適切に使用する必要があります。

3.プロトタイプパターンの構造と実現

Javaはオブジェクトのclone()メソッドを提供するため、Javaでプロトタイプモードを実装するのは非常に簡単です。

  • モデルの構造(プロトタイプモデルには次の主な役割が含まれています)
  1. 抽象プロトタイプクラス:具象プロトタイプオブジェクトが実装する必要のあるインターフェースを指定します。
  2. 具象プロトタイプクラス:コピー可能なオブジェクトである抽象プロトタイプクラスのclone()メソッドを実装します。
  3. アクセスクラス:具象プロトタイプクラスのclone()メソッドを使用して、新しいオブジェクトをコピーします。

構造図を図1に示します。

ここに画像の説明を挿入します

  • プロトタイプのクローン作成は、浅いクローン作成と深いクローン作成に分けられます。

    • 浅いクローン:新しいオブジェクトを作成します。新しいオブジェクトのプロパティは元のオブジェクトとまったく同じです。非基本タイプのプロパティの場合でも、元のプロパティが指すオブジェクトのメモリアドレスを指します。
    • ディープクローン:新しいオブジェクトを作成します。属性で参照されている他のオブジェクトもクローンされ、元のオブジェクトアドレスを指しなくなります。

3.1浅いコピー

JavaのObjectクラスは、浅いクローンのclone()メソッドを提供します。具体的なプロトタイプクラスは、オブジェクトの浅いクローンを実現するためにCloneableインターフェイスを実装するだけで済みます。ここでのCloneableインターフェイスは、抽象プロトタイプクラスです。コードは次のとおりです。

//具体原型类
class Realizetype implements Cloneable {
    
    
    Realizetype() {
    
    
        System.out.println("具体原型创建成功!");
    }

    public Object clone() throws CloneNotSupportedException {
    
    
        System.out.println("具体原型复制成功!");
        return (Realizetype) super.clone();
    }
}

//原型模式的测试类
public class PrototypeTest {
    
    
    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        Realizetype obj1 = new Realizetype();
        Realizetype obj2 = (Realizetype) obj1.clone();
        System.out.println("obj1==obj2?" + (obj1 == obj2));
    }
}

プログラムの実行結果は次のとおりです。

具体的なプロトタイプが無事に作成されました!
具体的なプロトタイプが正常にコピーされました!
obj1 == obj2?false

3.2ディープコピー

  1. オブジェクトのすべての基本的なデータ型メンバー変数値をコピーします
  2. 参照データ型のすべてのメンバー変数のストレージスペースを申請し、オブジェクトが到達可能なすべてのオブジェクトまで、つまり、各参照データ型変数によって参照されるオブジェクトをコピーします。オブジェクトのディープコピーには、オブジェクト全体(参照データ型を含む)のディープコピーが必要です。
  3. 方法1:clone()を書き換える
  4. 方法2:オブジェクトのシリアル化によるディープコピー
  5. clone()メソッドを使用するには、クラスはCloneableインターフェイスを実装する必要があり、シリアル化するには、Serializableインターフェイスを実装する必要があります。

電話クラス

public class Phone implements Serializable,Cloneable {
    
    
 
    private Integer telNumber;
    private String phoneType;
 
    public Phone(Integer telNumber, String phoneType) {
    
    
        this.telNumber = telNumber;
        this.phoneType = phoneType;
    }
 
    public String getPhoneType() {
    
    
        return phoneType;
    }
 
    public void setPhoneType(String phoneType) {
    
    
        this.phoneType = phoneType;
    }
 
    public Integer getTelNumber() {
    
    
        return telNumber;
    }
 
    public void setTelNumber(Integer telNumber) {
    
    
        this.telNumber = telNumber;
    }
 
    @Override
    public String toString() {
    
    
        return "Phone{" +
                "telNumber=" + telNumber +
                ", phoneType='" + phoneType + '\'' +
                '}';
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }
}
public class StudentDeepClone implements Serializable,Cloneable {
    
    
 
    private int id;
    private String name;
    private Phone phone;
 
    public StudentDeepClone(int id, String name, Phone phone) {
    
    
        this.id = id;
        this.name = name;
        this.phone = phone;
    }
 
    public int getId() {
    
    
        return id;
    }
 
    public void setId(int id) {
    
    
        this.id = id;
    }
 
    public String getName() {
    
    
        return name;
    }
 
    public void setName(String name) {
    
    
        this.name = name;
    }
 
    public Phone getPhone() {
    
    
        return phone;
    }
 
    public void setPhone(Phone phone) {
    
    
        this.phone = phone;
    }
 
    @Override
    public String toString() {
    
    
        return "StudentDeepClone{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", phone=" + phone +
                '}';
    } 
}

メソッド1:clone()メソッドを書き直します

//深拷贝 方式1 使用clone方法。里面的引用类型需要实现Cloneable接口
@Override
protected Object clone() throws CloneNotSupportedException {
    
    
	StudentDeepClone student = null;
	try {
    
    
		//实现对基本数据类型的拷贝
		student = (StudentDeepClone) super.clone();
		//实现对引用数据类型的拷贝
		student.setPhone((Phone)phone.clone());
	}catch (Exception e){
    
    
		e.printStackTrace();
	}
	return student;
}

方法2:オブジェクトのシリアル化によるディープコピーを使用する

//深拷贝 2 使用序列化方式
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);
		StudentDeepClone s = (StudentDeepClone) ois.readObject();
		return s;
	}catch (Exception e){
    
    
		e.printStackTrace();
		return null;
	}finally {
    
    
		try {
    
    
			bos.close();
			oos.close();
			bis.close();
			ois.close();
		}catch (Exception e){
    
    
			e.printStackTrace();
		}
	}
}

4.プロトタイプモードのアプリケーションシナリオ

プロトタイプモードは通常、次のシナリオに適しています

  • オブジェクトは同じまたは類似しています。つまり、いくつかの個別のプロパティのみが異なる場合です。
  • 初期化時間が長い、CPU使用率が高すぎる、ネットワークリソースが多すぎるなど、オブジェクトの作成コストは比較的高くなります。リソースを最適化する必要があります。
  • オブジェクトの作成には、面倒なデータの準備やアクセス許可などが必要であり、パフォーマンスやセキュリティを向上させる必要があります。
  • このタイプのオブジェクトはシステムで広く使用されており、各呼び出し元はそのプロパティを再割り当てする必要があります。

春には、プロトタイプパターンが広く使用されています。たとえばscope='prototype'JSON.parseObject()プロトタイプパターンの特定のアプリケーションなどです。

5.プロトタイプモードの拡張

プロトタイプモードは、プロトタイプマネージャーを使用してプロトタイプモードに拡張できます。プロトタイプマネージャーは、プロトタイプモードに基づいてプロトタイプマネージャーPrototypeManagerクラスを追加します。このクラスはHashMapを使用して複数の複製されたプロトタイプを格納し、Clientクラスはマネージャーのget(String id)メソッドから複製されたプロトタイプを取得できます。構造図を図5に示します。

ここに画像の説明を挿入します

例:プロトタイプマネージャーでプロトタイプモードを使用して、「円」や「正方形」などのグラフィックを含むプロトタイプを生成し、それらの面積を計算します。分析:この例では、「円」と「正方形」などのグラフィッククラスが異なるため、面積の計算方法が異なるため、それらを管理するにはプロトタイプマネージャーが必要です。図6にその構造を示します。

ここに画像の説明を挿入します

プログラムコードは次のとおりです。

import java.util.*;

interface Shape extends Cloneable {
    
    
    public Object clone();    //拷贝

    public void countArea();    //计算面积
}


// ==================================================

class Circle implements Shape {
    
    
    public Object clone() {
    
    
        Circle w = null;
        try {
    
    
            w = (Circle) super.clone();
        } catch (CloneNotSupportedException e) {
    
    
            System.out.println("拷贝圆失败!");
        }
        return w;
    }

    public void countArea() {
    
    
        int r = 0;
        System.out.print("这是一个圆,请输入圆的半径:");
        Scanner input = new Scanner(System.in);
        r = input.nextInt();
        System.out.println("该圆的面积=" + 3.1415 * r * r + "\n");
    }
}
// ==================================================
class Square implements Shape {
    
    
    public Object clone() {
    
    
        Square b = null;
        try {
    
    
            b = (Square) super.clone();
        } catch (CloneNotSupportedException e) {
    
    
            System.out.println("拷贝正方形失败!");
        }
        return b;
    }

    public void countArea() {
    
    
        int a = 0;
        System.out.print("这是一个正方形,请输入它的边长:");
        Scanner input = new Scanner(System.in);
        a = input.nextInt();
        System.out.println("该正方形的面积=" + a * a + "\n");
    }
}
class ProtoTypeManager {
    
    
    private HashMap<String, Shape> ht = new HashMap<String, Shape>();

    public ProtoTypeManager() {
    
    
        ht.put("Circle", new Circle());
        ht.put("Square", new Square());
    }

    public void addshape(String key, Shape obj) {
    
    
        ht.put(key, obj);
    }

    public Shape getShape(String key) {
    
    
        Shape temp = ht.get(key);
        return (Shape) temp.clone();
    }
}
public class ProtoTypeShape {
    
    
    public static void main(String[] args) {
    
    
        ProtoTypeManager pm = new ProtoTypeManager();
        Shape obj1 = (Circle) pm.getShape("Circle");
        obj1.countArea();
        Shape obj2 = (Shape) pm.getShape("Square");
        obj2.countArea();
    }
}

6.まとめ

  1. 新しいオブジェクトの作成がより複雑な場合は、プロトタイプモードを使用して、オブジェクト作成プロセスを簡素化し、効率を向上させることができます。
  2. オブジェクトを再初期化する必要はありませんが、オブジェクトの実行状態を動的に取得します。
  3. 元のオブジェクトが変更されると、コードを変更せずに、他の複製されたオブジェクトもそれに応じて変更されます。

おすすめ

転載: blog.csdn.net/saienenen/article/details/111661877