原型模式-克隆生成對象

一, 舉個業務場景來講明 java

如今咱們有個訂單系統,裏面有個保存訂單的業務功能。這個功能有個需求,就是每當訂單產品數量超過1000的時候,系統自動拆分訂單,拆分後的全部訂單中的產品數量依然不能超過1000,若是超過繼續拆分。(有同窗這裏可能會問,爲何限制產品1000?咱們這裏爲了方便訂單跟蹤工做分配緣由,人工訂單處理小組的處理能力爲1000) 程序員

怎麼實現呢? 設計模式

二:不使用設計模式來實現需求,直接上代碼吧 ide


/**
 * 訂單接口
 */
public interface OrderApi {
    public int getOrderProductNum();

    public void setOrderProductNum(int num);

    public String getOrderInfo();
}



/**
 * 我的訂單
 */
public class PersonalOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public PersonalOrder() {}

    public PersonalOrder(String customName, int productId,int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<我的訂單>,訂購人:"+this.customName+",訂購產品:"+this.productId+",訂購數量:"+this.orderProductNum;
    }
}



/**
 * 企業訂單
 */
public class EnterpriseOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public EnterpriseOrder() {
    }

    public EnterpriseOrder(String customName, int productId,int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<企業訂單>,訂購人:"+this.customName+",訂購產品:"+this.productId+",訂購數量:"+this.orderProductNum;
    }
}


ok,訂單接口定義完了, 測試

從我代碼中能夠看到咱們這裏有兩種訂單類型,我的訂單和企業訂單, this

下面繼續寫訂單處理類: spa

(考慮到每一個訂單有可能產品數量超過1000,就意味着繼續拆單,因此咱們要用到循環) 設計


/**
 * 訂單處理對象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判斷產品數量是否大於1000
        while (order.getOrderProductNum()>1000) {
            //若是大於繼續拆分
            //再建立一份訂單
            OrderApi newOrder = null;
            //如何建立??
        }
    }
}


這裏我先否則代碼一步到位,咱們來思考一個問題,拆分後的新訂單如何建立??? code

難道咱們要new 個訂單嗎,那麼new 哪一種類型的訂單呢? 對象

是new 我的訂單,仍是企業訂單?你根本沒法斷定!

小白這裏確定傻眼了,

但有經驗的程序員,確定會指出一個簡單的辦法,就是使用instanceof來斷定訂單類型

且看我代碼示例:


/**
 * 訂單處理對象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判斷產品數量是否大於1000
        while (order.getOrderProductNum()>1000) {
            //若是大於繼續拆分
            //再建立一份訂單
            OrderApi newOrder = null;
            if (order instanceof PersonalOrder){
                PersonalOrder p = (PersonalOrder) order;
                newOrder = new PersonalOrder(p.getCustomName(),p.getProductId(),1000);
            }else if(order instanceof EnterpriseOrder){
                EnterpriseOrder e = (EnterpriseOrder) order;
                newOrder = new EnterpriseOrder(e.getCustomName(),e.getProductId(),1000);
            }
            System.out.println(newOrder.getOrderInfo());
            order.setOrderProductNum(order.getOrderProductNum()-1000);
            //(後續業務代碼省略...)
        }
        System.out.println(order.getOrderInfo());
    }
}


咱們模擬個客戶端測試下: 測試下我的訂單和企業訂單


/**
 * 客戶端測試
 */
public class Client {
    public static void main(String[] args) {
        PersonalOrder personalOrder = new PersonalOrder("洋哥",6666,6925);
        OrderBusiness ob = new OrderBusiness();
        ob.saveOrder(personalOrder);
    }
}





/**
 * 客戶端測試
 */
public class Client {
    public static void main(String[] args) {
        EnterpriseOrder enterpriseOrder = new EnterpriseOrder("洋哥股份有限公司",518,5199);
        OrderBusiness ob = new OrderBusiness();
        ob.saveOrder(enterpriseOrder);
    }
}




以上訂單拆分功能實現基本知足需求!

可是若是我是你的leader的話, 這樣的代碼在review的時候,確定是沒法經過的!

這裏的問題就是出來訂單處理這個地方,從軟件工程學的角度來講訂單處理類是不須要關心甚至不須要知道具體訂單類型的!若是按照以上實現方式,那麼之後個人訂單類型增長了一個大企業訂單,那麼我是否是要修改訂單處理類,有人說了,添加幾行代碼很不麻煩的,那若是代碼不是你寫的呢?寫這個塊代碼的人已經離職或轉行了呢?何況修改代碼自己就不符合設計理念!所以上述實現方式確實不太好。

三,利用原型模式,從新實現的解決方案

原型模式的定義:用原型實例指定建立對象的種類,並經過拷貝這些原型建立新的對象。

 四,使用原型模式,從新實現,代碼示例


/**
 * 訂單接口
 */
public interface OrderApi {
    public int getOrderProductNum();

    public void setOrderProductNum(int num);

    public String getOrderInfo();

    /**
     * 原型模式增長代碼
     * @return 訂單原型的克隆實例
     */
    public OrderApi cloneOrder();
}


如何克隆呢?有的同窗可能想到 this  ,在克隆方法中直接返回this,這樣是打錯特錯了

/**
 * 我的訂單
 */
public class PersonalOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public PersonalOrder() {}

    public PersonalOrder(String customName, int productId,int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<我的訂單>,訂購人:"+this.customName+",訂購產品:"+this.productId+",訂購數量:"+this.orderProductNum;
    }
    /**
     * 原型模式增長代碼
     * @return 訂單原型的克隆實例
     */
    public OrderApi cloneOrder(){
        PersonalOrder order = new PersonalOrder(this.getCustomName(),this.productId,this.getOrderProductNum());
        return  order;
    }
}



/**
 * 企業訂單
 */
public class EnterpriseOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public EnterpriseOrder() {
    }

    public EnterpriseOrder(String customName, int productId, int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<企業訂單>,訂購單位:" + this.customName + ",訂購產品:" + this.productId + ",訂購數量:" + this.orderProductNum;
    }

    /**
     * 原型模式增長代碼
     *
     * @return 訂單原型的克隆實例
     */
    public OrderApi cloneOrder() {
        EnterpriseOrder order = new EnterpriseOrder(this.getCustomName(), this.productId, this.getOrderProductNum());
        return order;
    }
}



/**
 * 訂單處理對象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判斷產品數量是否大於1000
        while (order.getOrderProductNum()>1000) {
            //若是大於繼續拆分
            //再建立一份訂單
            OrderApi newOrder = order.cloneOrder();
            newOrder.setOrderProductNum(1000);
            System.out.println(newOrder.getOrderInfo());
            order.setOrderProductNum(order.getOrderProductNum()-1000);
            //(後續業務代碼省略...)
        }
        System.out.println(order.getOrderInfo());
    }
}



/**
 * 客戶端測試
 */
public class Client {
    public static void main(String[] args) {
        EnterpriseOrder enterpriseOrder = new EnterpriseOrder("洋哥股份有限公司",518518,6699);
        OrderBusiness ob = new OrderBusiness();
        ob.saveOrder(enterpriseOrder);
    }
}



有的同窗說了,java的Object自己就有克隆方法啊,還寫這麼麻煩?

雖然java有clone方法,但咱們本身實現出來也是頗有意義的,是爲了更好,跟完整第理解克隆模式,別急,標題六我會介紹如何使用java自帶的clone方法。

五,原型模式兩個功能

原型模式實際包含兩個功能:

1)經過克隆建立新的對象實例。

2)爲克隆出來的新對象實例複製原型實例屬性值。


六:java中的克隆,須要克隆功能的類只須要實現java.lang.Cloneable

/**
 * 訂單接口
 */
public interface OrderApi {
    public void setOrderProductNum(int orderProductNum);
    public int getOrderProductNum();
    public String getOrderInfo();
    public Object cloneOrder();
}



/**
 * 企業訂單
 */
public class EnterpriseOrder implements OrderApi,Cloneable {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public EnterpriseOrder() {
    }

    public EnterpriseOrder(String customName, int productId, int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }


    @Override
    public void setOrderProductNum(int orderProductNum) {
         this.orderProductNum = orderProductNum;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<企業訂單>,訂購單位:" + this.customName + ",訂購產品:" + this.productId + ",訂購數量:" + this.orderProductNum;
    }

    public Object cloneOrder(){
        Object object = null;
        try {
            //java內置克隆實現,直接調用父類的方法
            object = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return object;
    }
}



/**
 * 訂單處理對象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判斷產品數量是否大於1000
        while (order.getOrderProductNum()>1000) {
            //若是大於繼續拆分
            //再建立一份訂單
            OrderApi newOrder = (OrderApi) order.cloneOrder();
            newOrder.setOrderProductNum(1000);
            System.out.println(newOrder.getOrderInfo());
            order.setOrderProductNum(order.getOrderProductNum()-1000);
            //(後續業務代碼省略...)
        }
        System.out.println(order.getOrderInfo());
    }
}


測試結果和咱們本身實現的結果是如出一轍的!

我想這裏我有必要介紹下深度克隆和淺度克隆。

以上的代碼示例屬於淺度克隆!

咱們本身能夠實現深度克隆,就是要把須要克隆的類中的全部引用對象都要克隆!

固然咱們也可使用java自帶的克隆實現深度克隆,ok,以下圖代碼示例:

 七: 何時使用原型模式

1)若是一個系統想要獨立於它想要使用的對象時,可使用原型模式。

2)若是須要實例化的類是運行時動態指定時,可使用原型模式。

兩者,都是經過克隆獲得須要的實例

八:原型模式和抽象工廠的區別

兩者功能有些類似,都是動態獲取一個新對象實例。

不一樣之處在於,原型模式着眼於如何創造出實例,選擇的是克隆方式。而抽象工廠着眼點在於如何創造產品簇,至於如何建立產品簇中的產品對象實例,抽象工廠模式並不關心 。正由於關注點不同,兩者能夠配合使用。

相關文章
相關標籤/搜索