ps:本文係爲轉載,閱讀原文可獲取源碼,文章末尾有原文連接java
ps:這一篇是寫建造者模式、原型模式和適配器模式ide
**一、建造者模式
**測試
指將一個複雜對象的構造與它的表示分離,使一樣的構建過程能夠建立不一樣的表示;它是將一個複雜的對象分解爲多個簡單的對象,而後一步一步構建而成;建造者模式注重零部件的組裝過程。ui
建造者模式由如下幾個角色組成:this
(1)產品角色:它是一個複雜對象,包含多個組成部件,由具體建造者來建立其各個零部件。spa
(2)抽象建造者:它是一個包含建立產品每一個部件的抽象方法的抽象類,通常還提供返回複雜產品的方法。指針
(3)具體建造者:它是抽象建造者的子類,完成複雜產品的各個部件的具體建造方法。日誌
(4)指揮者:它調用建造者對象中的部件構造和組裝方法完成複雜對象的建造,包含定義組成部件的類,包括將這些部件裝配成最終產品的接口。code
產品角色,新建一個產品類 AirShip,它包含 OrbitalModel、Engine engine 和 EscapeTower 這幾個部件;orm
public class AirShip { private OrbitalModel orbitalModel; private Engine engine; private EscapeTower escapeTower; public OrbitalModel getOrbitalModel() { return orbitalModel; } public void setOrbitalModel(OrbitalModel orbitalModel) { this.orbitalModel = orbitalModel; } public Engine getEngine() { return engine; } public void setEngine(Engine engine) { this.engine = engine; } public EscapeTower getEscapeTower() { return escapeTower; } public void setEscapeTower(EscapeTower escapeTower) { this.escapeTower = escapeTower; } } class OrbitalModel { private String name; public OrbitalModel(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Engine { private String name; public Engine(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class EscapeTower { private String name; public EscapeTower(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
抽象建造者,新建一個 AirShipBuilder 接口,包含建立 OrbitalModel、Engine engine 和 EscapeTower 這幾個部件的抽象方法;
public interface AirShipBuilder { public OrbitalModel builderOrbitalModel(); public Engine builderEngine(); public EscapeTower builderEscapeTower(); }
具體建造者,新建一個類 MyAirShipBuilder 並實現 AirShipBuilder;
public class MyAirShipBuilder implements AirShipBuilder{ @Override public OrbitalModel builderOrbitalModel() { System.out.println("軌道艙"); return new OrbitalModel("個人軌道艙"); } @Override public Engine builderEngine() { System.out.println("發動機"); return new Engine("個人發動機"); } @Override public EscapeTower builderEscapeTower() { System.out.println("逃逸塔"); return new EscapeTower("個人逃逸塔"); } }
指揮者,新建一個類 MyAirShipDirector 並實現 AirShipDirector 接口,在當前類中用 directorAirShip 方法建造部件和組裝產品;
public interface AirShipDirector { public AirShip directorAirShip(); }
public class MyAirShipDirector implements AirShipDirector{ private AirShipBuilder builder; public MyAirShipDirector(AirShipBuilder builder) { super(); this.builder = builder; } @Override public AirShip directorAirShip() { Engine engine = builder.builderEngine(); OrbitalModel orbitalModel = builder.builderOrbitalModel(); EscapeTower escapeTower = builder.builderEscapeTower(); AirShip airShip = new AirShip(); airShip.setEngine(engine); airShip.setEscapeTower(escapeTower); airShip.setOrbitalModel(orbitalModel); return airShip; } }
在客戶端測試
AirShipDirector director = new MyAirShipDirector(new MyAirShipBuilder()); AirShip airShip = director.directorAirShip(); System.out.println(airShip.getEngine().getName()); System.out.println(airShip.getEscapeTower().getName()); System.out.println(airShip.getOrbitalModel().getName());
建造者模式封裝性好,擴展性好,每一個建造者相互獨立互補影響,便於解耦;在調用客戶端端時沒必要理會產品內部組成的細節,可是建造的部件和產品內部的部件必須相同,限制了建造的範圍;若是產品內部部件發生變化,那麼建造者也須要跟着更改。
二、原型模式
用一個已經存在的實例做爲原型,建立一個和原型相同類型的對象不須要 new,經過複製該原型對象就能夠建立一個和原型類似的新對象;這裏的原型對象和新對象不是同一個對象,而是它們同屬一個類。
原型模式有如下角色:
(1)抽象原型類:具體原型對象必須實現的接口 Cloneable。
(2)具體原型類:實現抽象原型類的 clone() 方法,返回一個被複制的對象。
(3)訪問類:也就是客戶端類調用具體原型類中的 clone() 方法來完成新的對象拷貝。
原型模式的克隆劃分爲淺克隆和深克隆;淺克隆就是對象的 clone 方法只會複製對象屬性中的基本的數據類型(8種基本數據類型),不會複製非基本的數據類型,非基本的數據類型仍是指向原型對象屬性的內存地址;深克隆就是把非基本數據類型的屬性也給複製過去,非基本數據類型的對象再也不指向原型對象的屬性地址;下面對2種克隆進行舉例;
二、1 淺克隆
因爲我是用 Java 代碼寫的,而 Java 沒有對指針進行擴展,因此這個基本數據類型很差驗證,咱們就驗證上面所說的非基本的數據類型仍是指向原型對象屬性的內存地址。
(1)抽象原型類,它是 Cloneable 接口,Java 內部提供,不用本身去新寫:
package java.lang; public interface Cloneable { }
(2)具體原型類,新建一個 Sheep 類並實現 Cloneable 接口:
public class Sheep implements Cloneable{ private String name; private Date birthday; public Sheep() { System.out.println("Sheep類對象無參構造方法"); } public Sheep(String name, Date birthday) { super(); this.name = name; this.birthday = birthday; System.out.println("Sheep類對象有2個參數的構造方法"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public Object clone() throws CloneNotSupportedException { Object object = super.clone(); return object; } }
(3)客戶端類,新建一個 Test 類,對 Sheep 類的原型對象進行克隆:
public class Test { public static void main(String[] args) { Date date = new Date(12345689l); String objectString = "原型對象----"; String objectString2 = "新對象----"; Sheep s1 = new Sheep("多利",date); System.out.println(objectString + s1); System.out.println(objectString + s1.getName()); System.out.println(objectString + s1.getBirthday()); System.out.println("________________________________"); try { Sheep s2 = (Sheep) s1.clone(); date.setTime(345466578887l); System.out.println(objectString2 + s2); System.out.println(objectString2 + s2.getName()); System.out.println(objectString2 + s2.getBirthday()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
日誌打印以下所示:
從日誌能夠看出,原型對象和新對象不是同一個對象,當咱們把原型對象克隆給新對象以後,再更改原型對象的屬性 date 的內容,發現新對象的屬性 date 內容也更改了,這就論證了上面說的,淺克隆不會複製非基本的數據類型。
二、2 深克隆
咱們來驗證非基本數據類型的對象再也不指向原型對象的屬性地址這句話。
(1)在上面淺克隆代碼的基礎上,咱們把 Sheep 類的 clone 方法修改一下,其餘的不變:
@Override public Object clone() throws CloneNotSupportedException { Object object = super.clone(); Sheep sheep = (Sheep) object; sheep.birthday = (Date) this.birthday.clone(); return object; }
(2)客戶端類不變,仍是和淺克隆的示例同樣調用:
Date date = new Date(12345689l); String objectString = "原型對象----"; String objectString2 = "新對象----"; Sheep s1 = new Sheep("多利",date); System.out.println(objectString + s1); System.out.println(objectString + s1.getName()); System.out.println(objectString + s1.getBirthday()); System.out.println("________________________________"); try { Sheep s2 = (Sheep) s1.clone(); date.setTime(345466578887l); System.out.println(objectString2 + s2); System.out.println(objectString2 + s2.getName()); System.out.println(objectString2 + s2.getBirthday()); } catch (CloneNotSupportedException e) { e.printStackTrace(); }
日誌打印以下:
客戶端這邊先對原型對象進行克隆獲得新對象,而後再改變原型對象 date 的內容,再輸出新對象的信息,發現新對象的 date 內容和原型對象剛初始化 date 內容同樣,說明了深克隆實現了非基本數據類型的對象再也不指向原型對象的屬性地址。
使用深克隆方式保存對象的狀態,使用原型模式拷貝,將其狀態保存起來,簡化了建立對象的過程;每一個被克隆的類必須實現 Cloneable 接口並重寫 clone 方法,從2個克隆的案例中能夠看出,使用原型模式拷貝對象不會調用類的構造方法,由於是經過調用 Object 類的 clone 方法實現的;原型模式和單例模式一塊兒用,單例模式就會失效,由於訪問權限 private 都對原型模式無效。
**三、適配器模式
**
將一個類的接口轉換成客戶指望的另外一個接口,它使得本來由於接口不兼容、不能一塊兒工做的一些類能夠在一塊兒工做。
適配器模式有如下角色:
(1)目標接口:客戶所期待的接口,目標能夠是抽象類,也能夠是接口,目標接口的實現類會使用接口方法調用適配者。
(2)適配者:它是被調用和適配的現存組件庫中的組件接口。
(3)適配器:它是一個轉換器,實現了目標接口,經過繼承或引用適配者的對象,把適配者接口轉換成目標接口,讓客戶用目標接口來調用適配者。
適配器模式可分爲類適配器模式和對象適配器模式,類適配器模式就是適配器繼承適配者,用接口方法調用適配器繼承適配者過來的方法;對象適配器模式就是採用對象組合方式實現,適配器和適配者不存在關係,用接口方法調用適配者的方法。
**三、1 類適配器模式
**
(1)目標接口,新建一個接口 TargetInterface:
public interface TargetInterface { public void request(); }
(2)適配者,新建一個類 AdapteeClass:
public class AdapteeClass { public void performRequest() { System.out.println("適配者的performRequest方法被執行"); } }
(3)適配器,新建一個類 AdapterClass,繼承 AdapteeClass 並實現 TargetInterface 接口:
public class AdapterClass extends AdapteeClass implements TargetInterface{ @Override public void request() { performRequest(); } }
(4)在客戶端進行調用:
TargetInterface targetInterface = new AdapterClass(); targetInterface.request();
**三、2 對象適配器模式
**
(1)在類適配器模式的狀況下,咱們再也不新建目標接口和適配者,這裏新建另一個適配器,類名叫 Adapter2Class 並實現目標接口 TargetInterface:
public class Adapter2Class implements TargetInterface{ private AdapteeClass adapteeClass; public Adapter2Class(AdapteeClass adapteeClass) { this.adapteeClass = adapteeClass; } @Override public void request() { adapteeClass.performRequest(); } }
(2)在客戶端進行調用:
AdapteeClass adapteeClass = new AdapteeClass(); TargetInterface targetInterface = new Adapter2Class(adapteeClass); targetInterface.request();
對象適配器模式中的適配器擁有一個適配者對象的屬性,把這個具體的特殊功能委託給適配者對象來實現;使用對象適配器模式,可使得適配器根據傳入的適配者對象或者適配者子類對象達到適配多個不一樣被適配的功能;不論是類適配器模式仍是對象適配器模式,它具備靈活性,只需修改適配器類和客戶端的代碼就能夠了。
對於對象適配器來講,更換適配器的實現過程不簡單;對於類適配器來講,比較單一,一個適配器只能有一個適配者;經過適配器,客戶端能夠調用同一接口,對客戶端來講是透明的;類適配者複用了現存的類,開發者不須要修改原有代碼而重用現有的適配者類;將目標類和適配者類解耦,解決了目標類和適配者類接口不一致的問題,就比如插座口和手機充電口插頭。