天天看點

Java設計模式(五)原型模式原型模式

原型模式

定義

是指原型執行個體指定建立對象的種類,并且通過拷貝這些原型建立新的對象
調用者不需要知道建立細節,不調用建構函數
屬于建立型模式
           

原型模式的核心在于拷貝原型對象。以系統中已經存在的一個對象為原型,直接基于記憶體二進制流進行拷貝,無需在經曆耗時的對象初始化過程(不調用構造函數),性能提升許多。當對象的建構比較耗時時,可以利用目前系統中已經存在的對象作為原型,對其進行克隆,進而躲避初始化過程,使得新對象的建立時間大大較少。

适用場景

1. 類初始化小号資源較多
2. new産生一個對象需要非常繁瑣的過程(資料準備,通路權限等)
3. 構造函數比較複雜
4. 循環體中生産大量對象
           

原型模式的通用寫法

public interface IPrototype<T> {
    T clone();
}


public class ConcretePrototype implements IPrototype{

    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public ConcretePrototype clone() {
//        ConcretePrototype concretePrototype = new ConcretePrototype();
//        concretePrototype.setAge(this.age);
//        concretePrototype.setName(this.name);
//        return concretePrototype;

        try {
            return (ConcretePrototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}
           
public class BeanUtils {
    public static Object copy(Object prototype) {
        Class clazz = prototype.getClass();
        Object returnValue = null;
        try {
            returnValue = clazz.newInstance();
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                field.set(returnValue, field.get(prototype));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnValue;
    }
}
           

通過反射調用原型中的屬性,指派到新的對象中。

原型模式之淺克隆

Cloneable接口:cloneable其實就是一個标記接口,隻有實作這個接口後,然後在類中重寫Object中的clone方法,然後通過類調用clone方法才能克隆成功,如果不實作這個接口,則會抛出CloneNotSupportedException(克隆不被支援)異常

public class ConcretePrototype implements Cloneable{

    private int age;
    private String name;
    private List<String> hobbies;
    

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

clone方法并不是把原型對象的引用指派為克隆對象,而是在堆中重新開辟空間,将原型對象複制過去,将新的位址傳回給克隆對象。但是對于原型對象中的引用對象,複制到克隆對象中的仍然是對象的引用,其對象不會發生改變。

原型模式之深克隆

深克隆的實作友兩種方式:

1. 序列化

2. json

public class ConcretePrototype implements Cloneable, Serializable {

    private int age;
    private String name;
    private List<String> hobbies;

    public ConcretePrototype 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);
            return (ConcretePrototype) ois.readObject();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
           

優點

  1. 性能優良,Java自帶的原型模式是基于二進制流的拷貝,比直接new一個對象性能上提升很多
  2. 可以使用深克隆方式儲存對象的狀态,使用原型模式将對象複制一份并将其狀态儲存,簡化了建立對象的過程,以便需要的時候使用(例如恢複到曆史某一狀态),可以輔助實作撤銷操作

缺點

  1. 需要為每一個類配置一個克隆方法
  2. 克隆方法位于類的内部,當對已有的類進行改造的時候,需要修改代碼,違反開閉原則。
  3. 在實作深克隆時需要編寫較為複雜的代碼,而且當對象之間存在多重嵌套應用時,為了實作深克隆,每一層對象對應的類都必須支援深克隆,實作比較麻煩。