設計模式:原型模式

設計模式:原型模式


定義

原型模式的定義:Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.(用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。)

結構類圖

原型模式的通用類圖:

原型模式的通用類圖

原型模式非常簡單,它的核心是一個clone方法,通過該方法完成對象的拷貝,在Java中只需要實現Cloneable接口,並且覆蓋Object類的clone方法。

通用源碼

原型模式的通用源碼:

public class PrototypeClass implements Cloneable {

    //覆寫父類Object方法
    @Override
    protected PrototypeClass clone() {
        PrototypeClass prototypeClass = null;
        try {
            prototypeClass = (PrototypeClass) super.clone();
        } catch (CloneNotSupportedException e) {
            // 異常處理
        }
        return prototypeClass;
    }

}

實現Cloneable接口,然後重寫clone方法,就完成了原型模式!

應用場景舉例

比如客戶提供訂單交給工廠處理。訂單有產品的數量和名稱,公司接受訂單後需要保存最原始的數據作爲存根。公司每個部門在一個訂單內最多隻能生產1000個產品,所以需要將原始訂單進行拆分,然後處理。

抽象訂單類IOrder,定義訂單數量和clone操作:

public interface IOrder extends Cloneable {

    int getOrderNumber();

    void setOrderNumber(int orderNumber);

    IOrder clone();
}

產生兩個訂單實現類,個人訂單類PersonalOrder:

public class PersonalOrder implements IOrder {

    private String orderName;
    private int orderNumber;

    @Override
    public int getOrderNumber() {
        return orderNumber;
    }

    @Override
    public void setOrderNumber(int orderNumber) {
        this.orderNumber = orderNumber;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

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

公司訂單類CompanyOrder:

public class CompanyOrder implements IOrder {

    private String orderName;
    private int orderNumber;

    @Override
    public int getOrderNumber() {
        return orderNumber;
    }

    @Override
    public void setOrderNumber(int orderNumber) {
        this.orderNumber = orderNumber;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

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

訂單處理類OrderDealFactory,將原始訂單進行拆分處理:

public class OrderDealFactory {

    public void dealOrder(IOrder order) {
        int number = order.getOrderNumber();
        while (number > 0) {
            /**
             * 如果不使用原型模式,需要根據實際類型new對象,來保存原始數據
            if (order instanceof PersonalOrder) {
                IOrder iOrder = null;
                PersonalOrder personalOrder = (PersonalOrder) order;
                PersonalOrder newOrder = new PersonalOrder();
                newOrder.setOrderName(personalOrder.getOrderName());
                newOrder.setOrderNumber(number >= 1000 ? 1000 : number);
                iOrder = personalOrder;
                System.out.println("原始訂單: " + iOrder.getOrderNumber());
                System.out.println("newOrder number = " + newOrder.getOrderNumber());
                number -= 1000;
            }
             */

            IOrder newOrder = (IOrder) order.clone();
            newOrder.setOrderNumber(number >= 1000 ? 1000 : number);
            System.out.println("原始訂單: " + order.getOrderNumber());
            System.out.println("newOrder number = " + newOrder.getOrderNumber());
            number -= 1000;
        }
    }

}

場景類的調用方法如下:

public class Client {

    public static void main(String[] args) {
        OrderDealFactory factory = new OrderDealFactory();
        PersonalOrder order = new PersonalOrder();
        order.setOrderName("個人訂單");
        order.setOrderNumber(3200);
        factory.dealOrder(order);
    }

}

淺拷貝、深拷貝

Object類的clone方法的原理是從內存中(具體地說就是堆內存)以二進制流的方式進行拷貝,重新分配一個內存塊。所以是淺拷貝,拷貝對象內部的引用對象是不會被拷貝的。即:淺拷貝前後的對象,內部的數組和引用對象,指向的還是同一片內存。

總結

  • 原型模式是在內存二進制流的拷貝,要比直接new一個對象性能好很多。
  • 在上面的例子中,增加一個訂單類,訂單處理類不需要修改,符合開閉原則。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章