設計模式10—設計模式之原型模式(Prototype)(建立型)

來源:互聯網
上載者:User
1.情境模式

考慮這樣一個實際應用:訂單處理系統
裡面有一個儲存訂單的功能,當產品數量超過1000份以後,拆成兩份訂單,再超,那麼就再拆。直到每份訂單不超過1000為止,訂單有兩種,一個是個人訂單,一個是公司訂單,現在需要實現一個通用的訂單處理系統。
2.情境模式代碼(代碼很簡單,不一一講解了)

package demo08.prototype.example1;/** * 訂單的介面 */public interface OrderApi {/** * 擷取訂單產品數量 *  * @return 訂單中產品數量 */public int getOrderProductNum();/** * 設定訂單產品數量 *  * @param num *        訂單產品數量 */public void setOrderProductNum(int num);}
package demo08.prototype.example1;/** * 個人訂單對象 */public class PersonalOrder implements OrderApi {/** * 訂購人員姓名 */private String customerName;/** * 產品編號 */private String productId;/** * 訂單產品數量 */private int orderProductNum = 0;public int getOrderProductNum() {return this.orderProductNum;}public void setOrderProductNum(int num) {this.orderProductNum = num;}public String getCustomerName() {return customerName;}public void setCustomerName(String customerName) {this.customerName = customerName;}public String getProductId() {return productId;}public void setProductId(String productId) {this.productId = productId;}public String toString() {return "本個人訂單的訂購人是=" + this.customerName + ",訂購產品是=" + this.productId + ",訂購數量為=" + this.orderProductNum;}}
package demo08.prototype.example1;/** * 企業訂單對象 */public class EnterpriseOrder implements OrderApi {/** * 企業名稱 */private String enterpriseName;/** * 產品編號 */private String productId;/** * 訂單產品數量 */private int orderProductNum = 0;public int getOrderProductNum() {return this.orderProductNum;}public void setOrderProductNum(int num) {this.orderProductNum = num;}public String getEnterpriseName() {return enterpriseName;}public void setEnterpriseName(String enterpriseName) {this.enterpriseName = enterpriseName;}public String getProductId() {return productId;}public void setProductId(String productId) {this.productId = productId;}public String toString() {return "本企業訂單的訂購企業是=" + this.enterpriseName + ",訂購產品是=" + this.productId + ",訂購數量為=" + this.orderProductNum;}}
package demo08.prototype.example1;/** * 處理訂單的業務對象 */public class OrderBusiness {/** * 建立訂單的方法 *  * @param order *        訂單的介面對象 */public void saveOrder(OrderApi order) {// 根據業務要求,當訂單的預定的產品數量超過1000的時候,就需要把訂單拆成兩份訂單// 當然如果要做好,這裡的1000應該做成常量,這麼做是為了示範簡單// 1:判斷當前的預定產品數量是否大於1000while (order.getOrderProductNum() > 1000) {// 2:如果大於,還需要繼續拆分// 2.1再建立一份訂單,跟傳入的訂單除了數量不一樣外,其他都相同OrderApi newOrder = null;if (order instanceof PersonalOrder) {// 建立相應的新的訂單對象PersonalOrder p2 = new PersonalOrder();// 然後進行賦值,但是產品數量為1000PersonalOrder p1 = (PersonalOrder) order;p2.setCustomerName(p1.getCustomerName());p2.setProductId(p1.getProductId());p2.setOrderProductNum(1000);// 然後再設定給newOrdernewOrder = p2;} else if (order instanceof EnterpriseOrder) {// 建立相應的訂單對象EnterpriseOrder e2 = new EnterpriseOrder();// 然後進行賦值,但是產品數量為1000EnterpriseOrder e1 = (EnterpriseOrder) order;e2.setEnterpriseName(e1.getEnterpriseName());e2.setProductId(e1.getProductId());e2.setOrderProductNum(1000);// 然後再設定給newOrdernewOrder = e2;}// 2.2原來的訂單保留,把數量設定成減少1000order.setOrderProductNum(order.getOrderProductNum() - 1000);// 然後是業務功能處理,省略了,列印輸出,看一下System.out.println("拆分產生訂單==" + newOrder);}// 3:不超過,那就直接業務功能處理,省略了,列印輸出,看一下System.out.println("訂單==" + order);}//public void saveOrder2(OrderApi order){//int oldNum = order.getOrderProductNum();//while(oldNum > 1000){////定義一個表示被拆分出來的新訂單對象//OrderApi newOrder = null;////if(order instanceof PersonalOrder){////建立相應的訂單對象//PersonalOrder p2 = new PersonalOrder();////然後進行賦值等,省略了////然後再設定給newOrder//newOrder = p2;//}else if(order instanceof EnterpriseOrder){////建立相應的訂單對象//EnterpriseOrder e2 = new EnterpriseOrder();////然後進行賦值等,省略了////然後再設定給newOrder//newOrder = e2;//}////然後進行拆分和其他業務功能處理,省略了//}//}}
package demo08.prototype.example1;public class OrderClient {public static void main(String[] args) {// 建立訂單對象,這裡為了示範簡單,直接new了PersonalOrder op = new PersonalOrder();// 設定訂單資料op.setOrderProductNum(2925);op.setCustomerName("張三");op.setProductId("P0001");// 這裡擷取業務處理的類,也直接new了,為了簡單,連業務介面都沒有做OrderBusiness ob = new OrderBusiness();// 調用業務來儲存訂單對象ob.saveOrder(op);}}
3.問題所在

仔細觀察可以發現:實際上是關注訂單的類型和具體實現的。證據如下:

// 1:判斷當前的預定產品數量是否大於1000while (order.getOrderProductNum() > 1000) {// 2:如果大於,還需要繼續拆分// 2.1再建立一份訂單,跟傳入的訂單除了數量不一樣外,其他都相同OrderApi newOrder = null;if (order instanceof PersonalOrder) {// 建立相應的新的訂單對象PersonalOrder p2 = new PersonalOrder();// 然後進行賦值,但是產品數量為1000PersonalOrder p1 = (PersonalOrder) order;p2.setCustomerName(p1.getCustomerName());p2.setProductId(p1.getProductId());p2.setOrderProductNum(1000);// 然後再設定給newOrdernewOrder = p2;} else if (order instanceof EnterpriseOrder) {// 建立相應的訂單對象EnterpriseOrder e2 = new EnterpriseOrder();// 然後進行賦值,但是產品數量為1000EnterpriseOrder e1 = (EnterpriseOrder) order;e2.setEnterpriseName(e1.getEnterpriseName());e2.setProductId(e1.getProductId());e2.setOrderProductNum(1000);// 然後再設定給newOrdernewOrder = e2;}// 2.2原來的訂單保留,把數量設定成減少1000order.setOrderProductNum(order.getOrderProductNum() - 1000);// 然後是業務功能處理,省略了,列印輸出,看一下System.out.println("拆分產生訂單==" + newOrder);}
4.解決方案

是不是覺得上面代碼很臃腫,很不爽,很不舒服,對頭,這樣說明你已經開始理解java設計模式的好處了。
解決它的方法就是使用原型模式
5.原型模式5.1原型模式定義:

用原型執行個體指定建立對象的種類,並通過拷貝這些原型創新新的對象。
5.2如何解決

那麼如何解決呢?大家有沒有想過可以把這些複製的代碼放在介面中,返回介面對象,這樣就好像是介面建立了介面對象似的。而且,用戶端就不用理解對象的一些操作了,知識最少化。
6.原型模式範例程式碼6.1模式結構圖

 
6.2聲明一個複製自身的介面

package demo08.prototype.example2;/** * 聲明一個複製自身的介面 */public interface Prototype {/** * 複製自身的方法 * @return 一個從自身複製出來的對象 */public Prototype clone();}
6.3具體的實現對象
package demo08.prototype.example2;/** * 複製的具體實現對象 */public class ConcretePrototype1 implements Prototype {public Prototype clone() {//最簡單的複製,建立一個自身對象,由於沒有屬性,就不去複製值了Prototype prototype = new ConcretePrototype1();return prototype;}}package demo08.prototype.example2;/** * 複製的具體實現對象 */public class ConcretePrototype2 implements Prototype {public Prototype clone() {//最簡單的複製,建立一個自身對象,由於沒有屬性,就不去複製值了Prototype prototype = new ConcretePrototype2();return prototype;}}
6.4用戶端
package demo08.prototype.example2;/** * 使用原型的用戶端 */public class Client {/** * 持有需要使用的原型介面對象 */private Prototype prototype;/** * 構造方法,傳入需要使用的原型介面對象 *  * @param prototype *        需要使用的原型介面對象 */public Client(Prototype prototype) {this.prototype = prototype;}/** * 示意方法,執行某個功能操作 */public void operation() {// 會需要建立原型介面的對象Prototype newPrototype = prototype.clone();}}
7.使用原型模式來重寫範例程式碼

為了方便我就直接寫改動的地方
7.1訂單的介面

package demo08.prototype.example3;/** * 訂單的介面,聲明了可以複製自身的方法 */public interface OrderApi {/** * 擷取訂單產品數量 * @return 訂單中產品數量 */public int getOrderProductNum();/** * 設定訂單產品數量 * @param num 訂單產品數量 */public void setOrderProductNum(int num);/** * 複製方法 * @return 訂單原型的執行個體 */public OrderApi cloneOrder();}
7.2個人訂單
package demo08.prototype.example3;/** * 個人訂單對象 */public class PersonalOrder implements OrderApi{/** * 訂購人員姓名 */private String customerName;/** * 產品編號 */private String productId;/** * 訂單產品數量 */private int orderProductNum = 0;public int getOrderProductNum() {return this.orderProductNum;}public void setOrderProductNum(int num) {this.orderProductNum = num;}public String getCustomerName() {return customerName;}public void setCustomerName(String customerName) {this.customerName = customerName;}public String getProductId() {return productId;}public void setProductId(String productId) {this.productId = productId;}public String toString(){return "本個人訂單的訂購人是="+this.customerName+",訂購產品是="+this.productId+",訂購數量為="+this.orderProductNum;}public OrderApi cloneOrder() {//建立一個新的訂單,然後把本執行個體的資料複製過去PersonalOrder order = new PersonalOrder();order.setCustomerName(this.customerName);order.setProductId(this.productId);order.setOrderProductNum(this.orderProductNum);return order;}}
7.3企業訂單
package demo08.prototype.example3;/** * 企業訂單對象 */public class EnterpriseOrder implements OrderApi {/** * 企業名稱 */private String enterpriseName;/** * 產品編號 */private String productId;/** * 訂單產品數量 */private int orderProductNum = 0;public int getOrderProductNum() {return this.orderProductNum;}public void setOrderProductNum(int num) {this.orderProductNum = num;}public String getEnterpriseName() {return enterpriseName;}public void setEnterpriseName(String enterpriseName) {this.enterpriseName = enterpriseName;}public String getProductId() {return productId;}public void setProductId(String productId) {this.productId = productId;}public String toString() {return "本企業訂單的訂購企業是=" + this.enterpriseName + ",訂購產品是=" + this.productId + ",訂購數量為=" + this.orderProductNum;}public OrderApi cloneOrder() {// 建立一個新的訂單,然後把本執行個體的資料複製過去EnterpriseOrder order = new EnterpriseOrder();order.setEnterpriseName(this.enterpriseName);order.setProductId(this.productId);order.setOrderProductNum(this.orderProductNum);return order;}}
7.4處理訂單的業務對象
package demo08.prototype.example3;/** * 處理訂單的業務對象 */public class OrderBusiness {/** * 建立訂單的方法 * @param order 訂單的介面對象 */public void saveOrder(OrderApi order){//根據業務要求,當訂單的預定的產品數量超過1000的時候,就需要把訂單拆成兩份訂單//當然如果要做好,這裡的1000應該做成常量,這麼做是為了示範簡單//1:判斷當前的預定產品數量是否大於1000while(order.getOrderProductNum() > 1000){//2:如果大於,還需要繼續拆分//2.1再建立一份訂單,跟傳入的訂單除了數量不一樣外,其他都相同OrderApi newOrder = order.cloneOrder();//然後進行賦值,產品數量為1000newOrder.setOrderProductNum(1000);//2.2原來的訂單保留,把數量設定成減少1000order.setOrderProductNum(order.getOrderProductNum()-1000);//然後是業務功能處理,省略了,列印輸出,看一下System.out.println("拆分產生訂單=="+newOrder);}//3:不超過,那就直接業務功能處理,省略了,列印輸出,看一下System.out.println("訂單=="+order);}}

這樣是不是簡單清爽了很多呢?
8.原型模式思考8.1原型模式的講解

通過複製建立新的對象執行個體
為複製出來的對象複製原型執行個體屬性的值,不是new而是類似new
8.2原型模式的調用順序圖

 
8.3淺度複製和深度複製

淺度複製:只負責按值傳遞的資料
深度複製:除了淺度複製複製的資料外,還要負責複製參考型別的資料,而且,參考型別還要遞迴複製
java也有複製方法,這裡就不說了。
體現深度複製的代碼如下(稍微更改一下就行了)
public OrderApi cloneOrder() {
//建立一個新的訂單,然後把本執行個體的資料複製過去
PersonalOrder order = new PersonalOrder();
order.setCustomerName(this.customerName);
order.setOrderProductNum(this.orderProductNum);
//對於物件類型的資料,深度複製的時候需要繼續調用這個對象的複製方法
order.setProduct((Product)this.product.cloneProduct());
return order;
}
8.4原型模式本質

複製產生對象
8.5原型模式優缺點

優點:對用戶端隱藏具體的實作類別型,運行時動態改變具體的實作類別型
缺點:每個原型的子類都要實現clone介面

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.