設計模式總綱——原型設計模式

   接上文,在小陳合理的推廣下,小陳的鋪貨量也是愈來愈大,愈來愈多,訂單數量也是愈來愈多,大到上市公司,運動品牌專賣店,小到街邊飾品小店等都來向小陳這邊進貨,可是隨着訂單的愈來愈多,如今天天的訂單量都要將近10萬量的計數,這時候一件讓小陳頭疼的事情來了,由於訂單量過於多,如今小陳那邊的出單機的速率已經跟不上了,由於本來出單機是一單單的打出來的,可是由於訂單量過於龐大,速度實在跟不上了,並且小陳認真的觀察了一下,訂單的格式都是差很少的,都是訂單時間,訂單數量,訂單的產品信息,預約公司的信息,基本上都是信息都是大同小異,咱們先來看看街邊小店的訂單格式:java

 1 public class OrderInfo {
 2     private String shopName;
 3     
 4     private String shopAddr;
 5     
 6     private String shopMobile;
 7     
 8     private String productName;
 9     
10     private String productNumber;
11 }//由於篇幅緣由,setter/getter方法就不寫了

街邊小店的訂單格式比較簡單,就基本信息和地址就是了,可是別看這種街邊小店,如今有將近3K家小店跟小陳的公司有合做,每月的營收可很多,有的時候小店的名字、地址、手機同樣,就產品和數量不同,又要從新生成一個訂單,有的是小店的開了分店,地址不同,可是其餘的信息又同樣,可是每一個訂單新生成的速度忒慢(若是每一個訂單都要生成,既浪費虛擬機的性能,並且每次填寫相同的信息也要花費不少時間),這個時候,小陳想既然都同樣,乾脆複製得了,而後再從新填上區別的信息,這樣就能夠一個訂單範本多家公司使用了。(你們能夠想一想爲何這裏不用工廠模式來生成訂單?)jvm

  接下來咱們就來看看怎麼來進行復制:ide

 1 public class OrderInfo implements Cloneable{
 2     private String shopName;
 3     private String shopAddr;
 4     private String shopMobile;
 5     private String productName;
 6     private String productNumber;
 7 
 8     @Override
 9     protected Object clone() {
10         try {
11             return super.clone();
12         } catch (CloneNotSupportedException e) {
13             e.printStackTrace();
14         }
15         return null;
16     }
17 }//由於篇幅緣由,setter/getter方法就不寫了

在這裏OrderInfo必須實現Cloneable,讓虛擬機知道該對象是可複製的,在這裏必須說明一點,clone對象不是Cloneable中的方法,若是咱們點進源代碼裏面看的話,會發現這個接口是個空接口,那這個clone方法是哪裏來的呢?Java裏面全部的對象都繼承自Object,因此clone方法是Object對象中的方法,咱們這裏是重寫了他的方法。好了,這樣的話,咱們來看看客戶端來怎麼生成,一家小店有兩家分店,除了地址其餘的信息都同樣的訂單了。性能

 1     @Test
 2     public void clien() {
 3         OrderInfo orderInfo = new OrderInfo("飾品小店", "北京王府井大街", "13888888888", "騎士徽章", "10000");
 4         
 5         OrderInfo cloneInfo = (OrderInfo)orderInfo.clone();
 6         
 7         cloneInfo.setShopAddr("北京王府井大街2號");
 8         
 9         System.out.println(orderInfo);
10         System.out.println(cloneInfo);
11     }

OrderInfo [shopName=飾品小店, shopAddr=北京王府井大街, shopMobile=13888888888, productName=騎士徽章, productNumber=10000]
OrderInfo [shopName=飾品小店, shopAddr=北京王府井大街2號, shopMobile=13888888888, productName=騎士徽章, productNumber=10000]ui

這裏的話,咱們能夠看到除了店面的地址不同,其餘的信息所有同樣了,這樣子就省去了不少成本了,訂單的生產速度也快了不止一個級別,小陳很是開心,可是這個時候,訂單出單員小A發現了個問題了,當訂單是街邊小店的訂單的時候,訂單會沒有問題,可是當是上市公司的訂單,或者品牌大店的訂單的時候,出單就會有問題,小陳觀察了一下,原來上市集團的大單的訂單格式是下面這種方式的:this

 1 public class OrderInfo implements Cloneable{
 2     private Product productInfo;
 3     private Company company;
 4     
 5     @Override
 6     protected Object clone() {
 7         try {
 8             return super.clone();
 9         } catch (CloneNotSupportedException e) {
10             e.printStackTrace();
11         }
12         return null;
13     }
14 }
15 
16 class Product {
17     private String productName;
18     private String productBuildeAddr;
19     private String productBuildeDate;
20     //...等一系列關於產品的信息,由於篇幅略過
21 }
22 
23 class Company {
24     private String companyName;
25     private String companyAddr;
26     private String companyMobile;
27     //...等一系列關於公司的信息,由於篇幅略過
28 }

大型公司的信息都比較完善,並且他們都把信息封裝到了一個個的對象中去了,訂單中展現出了一個個的對象,那爲何咱們clone的時候不起做用了呢?咱們再來看看客戶端的調用:spa

 1     @Test
 2     public void clien() {
 3         OrderInfo orderInfo = new OrderInfo(new Product("騎士徽章","克利夫蘭","20160601"),new Company("騎士公司", "北京騎士大道", "13666666666"));
 4         
 5         OrderInfo cloneInfo = (OrderInfo)orderInfo.clone();
 6         
 7         cloneInfo.getCompany().setCompanyAddr("北京騎士大道2號");
 8         
 9         System.out.println(orderInfo);
10         System.out.println(cloneInfo);
11     }

OrderInfo [productInfo=Product [productName=騎士徽章, productBuildeAddr=克利夫蘭, productBuildeDate=20160601], company=Company [companyName=騎士公司, companyAddr=北京騎士大道2號, companyMobile=13666666666]]
OrderInfo [productInfo=Product [productName=騎士徽章, productBuildeAddr=克利夫蘭, productBuildeDate=20160601], company=Company [companyName=騎士公司, companyAddr=北京騎士大道2號, companyMobile=13666666666]]code

咱們這裏就能夠看到了clone訂單更改了地址以後,原對象也更改了,這裏就涉及到了jvm虛擬中的對象的引用了。(說的簡單點就是,其實java中的每一個對象在jvm中算是一個引用,引用指向了堆中的對象,而咱們在克隆一個對象時,若是進行了淺拷貝的話,那只是將這個引用複製了一次,而沒有對這個對象進行克隆,因此會致使,對象的克隆失敗,由於兩個引用都指向了堆中的同一個對象,因此在這裏咱們就須要進行deep Clone),這裏的deep Clone有兩種方式:對象

一種就是對須要克隆的對象裏面的對象,所有實現clone的方法,那樣的話,clone的時候,他就會所有進行復制了,相似上文中的方法blog

 1 class Product implements Cloneable{
 2     @Override
 3     protected Object clone() {
 4         try {
 5             return super.clone();
 6         } catch (CloneNotSupportedException e) {
 7             e.printStackTrace();
 8         }
 9         return null;
10     }
11 }
12 
13 class Company implements Cloneable{
14     @Override
15     protected Object clone() {
16         try {
17             return super.clone();
18         } catch (CloneNotSupportedException e) {
19             e.printStackTrace();
20         }
21         return null;
22     }
23 }

這裏必須注意到的是,若是對象裏面還有對象的話,那就必須一直實現Cloneable。

 

接下來咱們重點介紹第二種方法:流式克隆

在流式克隆中,咱們這邊須要使用到Serializable這個接口,這個接口跟Cloneable同樣,也是標識接口,這個接口也是空方法,實現了該接口的對象被標識爲可序列化的

 1 public class OrderInfo implements Cloneable,Serializable{
 2     private Product productInfo;
 3     private Company company;
 4     
 5     @Override
 6     protected Object clone() {
 7         try {
 8             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 9             ObjectOutputStream oos = new ObjectOutputStream(baos);
10             oos.writeObject(this);
11             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
12             ObjectInputStream ois = new ObjectInputStream(bais);
13             return ois.readObject();
14         } catch (IOException e) {
15             e.printStackTrace();
16         } catch (ClassNotFoundException e) {
17             e.printStackTrace();
18         }
19         return null;
20     }
21 }

這裏對其進行IO操做是使用JVM中的將對象寫到流中是對象的一個拷貝的這一個特性,而源對象仍然保留在了jvm中,因此從新讀取出來的話又是一條好對象啦,可是這裏必須注意的是若是使用流式拷貝的話,那內部全部的被拷貝的對象都要實現Serializable這個接口,只須要實現Serializable接口便可,不須要其餘的操做。而後咱們再執行客戶端的操做就能夠看到,客戶端獲得的是兩個不一樣的對象了。

如今小陳又解決了一個問題了,如今訂單的問題也解決了,也再也不會被大量的訂單致使出貨慢,讓客戶投訴了,在創業的這段時間遇到了不一樣的問題,可是小陳有自信能夠一步步的解決掉,下回小陳還會遇到什麼樣的問題呢?

  欲知下回如何,且聽下文分解。

相關文章
相關標籤/搜索