Java程式設計師從笨鳥到菜鳥之(三十四)大話設計模式(五)建立者模式和原型模式
建立者模式是建立型模式中最負責的一個設計模式了,建立者負責構建一個物件的各個部分,並且完成組裝的過程.構建模式主要用來針對複雜產品生產,分離部件構建細節,以達到良好的伸縮性。把構造物件例項的邏輯移到了類的外部,在這個類外部定義了這個類的構造邏輯。它把一個複雜物件的構過程從物件的表示中分離出來。其直接效果是將一個複雜的物件簡化為一個比較簡單的物件。它強調的是產品的構造過程。
在軟體系統中,有時候面臨著“一個複雜物件”的建立工作,其通常由各個部分的子物件用一定的演算法構成;由於需求的變化,這個複雜物件的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的演算法確相對穩定。如何應對這種變化?如何提供一種“封裝機制”來隔離出“複雜物件的各個部分”的變化,從而保持系統中的“穩定構建演算法”不隨著需求改變而改變?這就是要說的建造者模式。
意圖:將一個複雜物件的構建與其表示相分離,使得同樣的構建過程可以建立不同的表示。
類圖:
抽象建造者(Builder):給出一個抽象介面,以規範產品物件的各個組成成分的建造。這個介面規定要實現複雜物件的哪些部分的建立,並不涉及具體的物件部件的建立。
具體建造者(Concrete Builder):實現Builder介面,針對不同的商業邏輯,具體化複雜物件的各部分的建立。 在建造過程完成後,提供產品的例項。
指導者(Director):呼叫具體建造者來建立複雜物件的各個部分,在指導者中不涉及具體產品的資訊,只負責保證物件各部分完整建立或按某種順序建立。
產品(Product
適用範圍:
1.需要生成的產品物件有複雜的內部結構。
2.需要生成的產品物件的屬性相互依賴,建造者模式可以強迫生成順序。
3.在物件建立過程中會使用到系統中的一些其他物件,這些物件在產品物件的建立過程中不易得到。
效果:
1.建造者模式的使用時的產品的內部表象可以獨立的變化。使用建造者模式可以使客戶端不必知道產品內部組成的細節。
2.每一個Builder都相對獨立,而與其他的Builder無關。
3.模式所建造的最終產品易於控制。
下面我們來看一下經典建立者模式的一個實現形式,然後針對這個經典模式後面提出幾個改進方案,我們這裡以上面講述的服裝的過程作為例子來說明下建立者模式的原理和思想,希望大家也能靈活的運用到實際的專案中去。達到學以致用的目的。
我們來看看具體的程式碼實現:
package builder;
public class Product {
ArrayList<String> parts = new ArrayList<String>();
public void add(String part)
{
parts.add(part);
}
public void show()
{
System.out.println("產品建立------------");
for(String part : parts)
{
System.out.println(part);
}
}
}
public abstract class Builder {
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract Product getResult();
}
public class ConcreteBuilder1 extends Builder{
private Product product = new Product();
@Override
public void BuildPartA() {
product.add("部件A");
}
@Override
public void BuildPartB() {
product.add("部件B");
}
@Override
public Product getResult() {
return product;
}
}
public class ConcreteBuilder2 extends Builder{
private Product product = new Product();
@Override
public void BuildPartA() {
product.add("部件x");
}
@Override
public void BuildPartB() {
product.add("部件y");
}
@Override
public Product getResult() {
return product;
}
}
public class Director {
public void Construct(Builder builder)
{
builder.BuildPartA();
builder.BuildPartB();
}
}
public class TestBuilder {
public static void main(String[] args) {
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBuilder2();
director.Construct(b1);
Product p1 = b1.getResult();
p1.show();
director.Construct(b2);
Product p2 = b2.getResult();
p2.show();
}
}
通過上面的程式碼,我們給出了經典建立者模式的核心程式碼形式,那麼針對上面無疑有以下的幾個缺點:
1、Ibuilder介面必須定義完整的組裝流程,一旦定義就不能隨意的動態修改。
2、Builder與具體的物件之間有一定的依賴關係,當然這裡可以通過介面來解耦來實現靈活性。
3、Builder必須知道具體的流程。
那麼針對上面的幾個問題,我們如何來解決呢?我想前面的建立型模式已經給我了足夠的經驗,還是通過配置檔案或者其他的形式來提供靈活性。
原型模式
用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件。 Prototype原型模式是一種建立型設計模式,Prototype模式允許一個物件再建立另外一個可定製的物件,根本無需知道任何如何建立的細節,工作原理是:通過將一個原型物件傳給那個要發動建立的物件,這個要發動建立的物件通過請求原型物件拷貝它們自己來實施建立。它主要面對的問題是:“某些結構複雜的物件”的建立工作;由於需求的變化,這些物件經常面臨著劇烈的變化,但是他們卻擁有比較穩定一致的介面。
原型模式最大的特點是克隆一個現有的物件,這個克隆的結果有2種,一種是是淺複製,另一種是深複製,這裡我們也會探討下深複製和淺複製的原理,這樣可能更方便大家理解這個原型模式的使用。我們都知道,建立型模式一般是用來建立一個新的物件,然後我們使用這個物件完成一些物件的操作,我們通過原型模式可以快速的建立一個物件而不需要提供專門的new()操作就可以快速完成物件的建立,這無疑是一種非常有效的方式,快速的建立一個新的物件。
原型模式的原理圖:
原型模式的主要思想是基於現有的物件克隆一個新的物件出來,一般是有物件的內部提供克隆的方法,通過該方法返回一個物件的副本,這種建立物件的方式,相比我們之前說的幾類建立型模式還是有區別的,之前的講述的工廠模式與抽象工廠都是通過工廠封裝具體的new操作的過程,返回一個新的物件,有的時候我們通過這樣的建立工廠建立物件不值得,特別是以下的幾個場景的時候,可能使用原型模式更簡單也效率更高。
主要運用場合:
1、如果說我們的物件型別不是剛開始就能確定,而是這個型別是在執行期確定的話,那麼我們通過這個型別的物件克隆出一個新的型別更容易。
2、有的時候我們可能在實際的專案中需要一個物件在某個狀態下的副本,這個前提很重要,這點怎麼理解呢,例如有的時候我們需要對比一個物件經過處理後的狀態和處理前的狀態是否發生過改變,可能我們就需要在執行某段處理之前,克隆這個物件此時狀態的副本,然後等執行後的狀態進行相應的對比,這樣的應用在專案中也是經常會出現的。
3、當我們在處理一些物件比較簡單,並且物件之間的區別很小,可能只是很固定的幾個屬性不同的時候,可能我們使用原型模式更合適
深複製和淺複製:
⑴淺複製(淺克隆)
被複制物件的所有變數都含有與原來的物件相同的值,而所有的對其他物件的引用仍然指向原來的物件。換言之,淺複製僅僅複製所考慮的物件,而不復制它所引用的物件。
⑵深複製(深克隆)
被複制物件的所有變數都含有與原來的物件相同的值,除去那些引用其他物件的變數。那些引用其他物件的變數將指向被複制過的新物件,而不再是原有的那些被引用的物件。換言之,深複製把要複製的物件所引用的物件都複製了一遍。
下面舉一個例項來實現以下原型模式:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Prototype implements Cloneable,Serializable{
private String str;
private Temp temp;
public Object clone()throws CloneNotSupportedException{ //淺克隆
Prototype prototype=(Prototype)super.clone();
return prototype;
}
public Object deepClone()throws IOException,ClassNotFoundException{ //深克隆
ByteArrayOutputStream bo=new ByteArrayOutputStream();
ObjectOutputStream oo=new ObjectOutputStream(bo);
oo.writeObject(this);
ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi=new ObjectInputStream(bi);
return oi.readObject();
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public Temp getTemp() {
return temp;
}
public void setTemp(Temp temp) {
this.temp = temp;
}
}
class Temp implements Serializable{
}
public class Test {
public static void main(String[] args)throws CloneNotSupportedException,ClassNotFoundException ,IOException{
Prototype pt=new Prototype();
Temp temp=new Temp();
pt.setTemp(temp);
pt.setStr("Hello World");
System.out.println("使用淺克隆方法進行建立物件");
Prototype pt1=(Prototype)pt.clone();
System.out.println("=============================");
System.out.println("比較pt和pt1的str的值:");
System.out.println(pt.getStr());
System.out.println(pt1.getStr());
System.out.println("修改pt1物件中str的值後,比較pt和pt1的str的值:");
pt1.setStr("你好,世界");
System.out.println(pt.getStr());
System.out.println(pt1.getStr());
System.out.println("============================");
System.out.println("比較pt和pt1中temp物件的值");
System.out.println(pt.getTemp());
System.out.println(pt1.getTemp());
System.out.println("使用深克隆方法進行建立物件");
System.out.println("============================");
pt1=(Prototype)pt.deepClone();
System.out.println(pt.getTemp());
System.out.println(pt1.getTemp());
}
}
輸出結果:使用淺克隆方法進行建立物件=============================比較pt和pt1的str的值:Hello WorldHello World修改pt1物件中str的值後,比較pt和pt1的str的值:Hello World你好,世界============================比較pt和pt1中temp物件的值[email protected][email protected]使用深克隆方法進行建立物件============================[email protected][email protected]
從上面的輸出結果我們可以看出使用Object.clone()方法只能淺層次的克隆,即只能對那些成員變數是基本型別或String型別的物件進行克隆,對哪些成員變數是類型別的物件進行克隆要使用到物件的序列化,不然克隆克隆出來的Prototype物件都共享同一個temp例項。
總結:
原型模式作為建立型模式中的最特殊的一個模式,具體的建立過程,是由物件本身提供,這樣我們在很多的場景下,我們可以很方便的快速的構建新
的物件,就像前面分析講解的幾類場景中,可能我們通過使用物件的克隆,比通過其他幾類的建立型模式,效果要好的多,而且代價也小很多。打個比方,
原型模式對於系統的擴充套件,可以做到無縫的擴充套件,為什麼這麼說呢?比如其他的建立型工廠,如果新增一個物件型別,那麼我們不管是修改配置檔案的方
式,還是修改程式碼的形式,無疑我們都是需要進行修改的,對於我們大家通用的公共應用來說這無疑是危險的,那麼通過原型模式,則可以解決這樣的問
題,因為型別本身實現這樣的方法即可,但是也有一定的缺點,每個物件都實現這樣的方法,無疑是很大的工作量,但是在某些特殊的環境下,或者實際的
專案中,可能原型模式是好的選擇。
相關推薦
Java程式設計師從笨鳥到菜鳥之(五十三)細談Hibernate(四)Hibernate常用配置檔案詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(一百)sql注入攻擊詳解(一)sql注入原理詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(一)開發環境搭建,基本語法,字串,陣列
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(一百零三)java操作office和pdf檔案(一)java讀取word,excel和pd
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(十四)Html基礎總結(上)
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(九十三)深入java虛擬機器(二)——類載入器詳解(上)
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(三十二)大話設計模式(二)設計模式分類和三種工廠模式
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(八十五)跟我學jquery(一)愛之初體驗jquery
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(四十八)細談struts2(十)ognl概念和原理詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(九十四)深入java虛擬機器(三)——類的生命週期 下)類的初始化
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(八十)細談Spring(九)spring+hibernate宣告式事務管理詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(七十三)細談Spring(五)spring之AOP底層大揭祕
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(二十四)Xml基礎詳解和DTD驗證 Java程式設計師從笨鳥到菜鳥之(二十三)常見亂碼解決以及javaBean基礎知識
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(八十二)細談Spring(十一)深入理解spring+struts2整合(附原始碼)
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(七十二)細談Spring(四)利用註解實現spring基本配置詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥之(八十一)細談Spring(十)深入原始碼分析Spring之HibernateTemplate
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java程式設計師從笨鳥到菜鳥(五十四) 分散式之訊息佇列
##目錄 該文只是一個複習思路,不瞭解訊息佇列的人建議先看《訊息佇列從入門到精通》 ##一、為什麼使用訊息佇列 三個最主要的應用場景:解耦、非同步、削峰 1、解耦 傳統模式: 缺點:系統間的耦合性太強,如上圖示,系統 A 在程式碼中直接呼叫系統 B 和
Java程式設計師從笨鳥到菜鳥之(七十四)細談Spring(六)spring之AOP基本概念和配置詳解
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興! 首先我們來看一下官方文件所給我們的關於AOP的一些概念性詞語的解釋:切面(Aspect):一個關注點的模組化,這個關注點可能會橫切多個物件。事務管
Java程式設計師從笨鳥到菜鳥之(九十三)深入java虛擬機器(二)——類的生命週期(上)類的載入和連線
類載入器,顧名思義,類載入器(class loader)用來載入 Java 類到 Java 虛擬機器中。一般來說,Java 虛擬機器使用 Java 類的方式如下:Java 源程式(.java 檔案)在經過 Java 編譯器編譯之後就被轉換成 Java 位元組程式碼(.class 檔案)。類載
Java程式設計師從笨鳥到菜鳥之(三十五)細談struts2 一)自己實現struts2框架
Struts最早是作為Apache Jakarta專案的組成部分,專案的創立者希望通過對該專案的研究,改進和提高JavaServer Pages 、Servlet、標籤庫以及面嚮物件的技術水準。最初的struts1.x很快在企業開發中流行了起來,與此同時,當時還有一個非常的優秀的web開發框架誕生,