一、建造者模式
本質:分離了對象子組件的單獨構造(由Builder負責)和裝配的分離(由Director負責),從而可以構建出復雜的對象,這個模式適用于:某個對象的構建過程十分復雜
好處:由于構建和裝配的解耦,不同的構建器和相同的裝配可以做出不同的對象,相同的構建器和不同裝配順序也可以組成不同的對象,實現了構建算法和裝配算法的解耦,
實現了更好的復用。
【基本模塊】
/**** "宇宙飛船"類*/ package cn.sxt.builder;public class Airship {private OrbitalModule orbitalModule;//軌道倉模塊private Engine engine;//發動機模塊private EscapeTower escapeTower;//逃逸塔模塊public OrbitalModule getOrbitalModule() {return orbitalModule;}public void setOrbitalModule(OrbitalModule orbitalModule) {this.orbitalModule = orbitalModule;}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;}public String toString() {String msg="配置:["+orbitalModule.getName()+engine.getName()+escapeTower.getName()+"]";return msg;}public void launch() {System.out.println(engine.getName()+"點火,5,4,3,2,1,發射!");} }class OrbitalModule{//"軌道倉"類private String name;public OrbitalModule(String name) {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) {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) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;} }
?
【建造者和裝配者】接口
/**** "建造類"接口,提供構建3個子類的方法*/ package cn.sxt.builder;public interface AirshipBuilder {OrbitalModule builderOrbitalModule();cn.sxt.builder.Engine builderEngine();EscapeTower builderEscapeTower(); }/**** "裝配類"接口, Director:導演,負責人*/ package cn.sxt.builder;public interface AirShipDirector {Airship directorAirship();//組裝飛船對象 }
【建造者和裝配者】具體實現類
/**** "神7飛船"子組件的建造者*/ package cn.sxt.builder;public class S7AirShipBuilder implements AirshipBuilder { //XML解析中,JDOM庫中的類:DOMBuilder也是建造者模式public OrbitalModule builderOrbitalModule() { System.out.println("--制造天宮牌軌道倉--");return new OrbitalModule("天宮牌軌道倉 ");}public Engine builderEngine() {System.out.println("--制造盤古牌發動機--");return new Engine("盤古牌發動機 "); }public EscapeTower builderEscapeTower() {System.out.println("--制造曹操牌逃逸塔--");return new EscapeTower("曹操牌逃逸塔");}}
/**** "神7飛船"裝配者*/ package cn.sxt.builder;public class S7AirShipDirector implements AirShipDirector{private AirshipBuilder builder;//要裝配的對象,要裝配什么組件public S7AirShipDirector(AirshipBuilder builder) {this.builder = builder;}public Airship directorAirship() {OrbitalModule oModule=builder.builderOrbitalModule();Engine engine=builder.builderEngine();EscapeTower eTower=builder.builderEscapeTower();//獲得各個組件 Airship ship=new Airship();//一個具體的飛船對象 ship.setOrbitalModule(oModule);ship.setEngine(engine);ship.setEscapeTower(eTower);return ship;}}
【客戶端】
/**** 客戶端*/ package cn.sxt.builder;public class Test_0424_Client {public static void main(String[] args) {AirshipBuilder builder=new S7AirShipBuilder();//飛船建造者AirShipDirector director=new S7AirShipDirector(builder);//飛船裝配者 Airship s7ship=director.directorAirship();System.out.println(s7ship);s7ship.launch();}}
?
二、原型模式(克隆模式、原型模式。prototype:原型、雛形)
? ? 通過new產生一個對象需要非常繁瑣的數據準備或者訪問權限,則可以使用原型模式。JavaScript中的繼承中使用過。
? ? 就是Java中的克隆技術,以某個對象為原型。new創建新的對象采用默認值。克隆出的對象的屬性值完全和原型相同,并且克隆出的新對象改變不會影響原型對象。
然后,再修改克隆對象的值。
?實現:通過Cloneable接口和clone方法,幫我們進行內存的復制操作。常常與工廠模式結合起來
用途:如果短時間需要創建大量對象,并且new的時候比較耗時間,可以用原型模式,效率大概是普通方法的100倍
【原型羊】
/**** 原型"羊"類*/ package cn.sxt.prototype; import java.util.Date;public class Sheep implements Cloneable {private String name;private Date birthday;@Override //重寫父類中的clone方法protected Object clone() throws CloneNotSupportedException {Object obj=super.clone();//直接調用Object類對象的clone方法/* //添加如下代碼2行實現深克隆Sheep s=(Sheep)obj;s.birthday=(Date)this.birthday.clone();//把屬性(出生日期)也進行克隆 */ return obj;}public Sheep() {super();}public Sheep(String name, Date birthday) {super();this.name = name;this.birthday = birthday;}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;}}
【克隆羊】
/*** 測試取克隆一只"羊"(淺克隆和深克隆)*/ package cn.sxt.prototype;import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date;public class Test_0424_Client01 {public static void main(String[] args) throws Exception {Date date=new Date(1000000L);Sheep s1=new Sheep("羊一代",date);//要克隆出新羊,需要原型"羊",這就是原型"羊" System.out.println(s1);System.out.println(s1.getName());System.out.println(s1.getBirthday());Sheep s2=(Sheep)s1.clone();//新建一個對象,但不是通過new,而是直接調用原型"羊"的clone方法System.out.println(s2);//輸出結果顯示s1與s2對象在內存中的值不同,但是屬性信息等一模一樣 System.out.println(s2.getName());System.out.println(s2.getBirthday());s2.setName("羊二代");//修改s2的屬性值,完全不影響s1的值 System.out.println(s2.getName());//修改原型"羊"的出生日期,看看克隆羊的出生日期/** 淺克隆:把原型羊的出生日期改了,但是影響克隆羊的出生日期* 深克隆:把原型羊的出生日期改了,但是不影響克隆羊的出生日期* 原理:* 淺克隆:s1----->data對象<-----s2(s1和s2的出生日期均執行同一時間對象data,s1一改動,s2也受影響)* 深克隆:s1----->data對象。data對象的復制品<-----s2,s1改動與s2沒有關系,s2的出生日期不會動* */date.setTime(40000000L);System.out.println(s1.getBirthday());System.out.println(s2.getBirthday());} }
?【深克隆方式之二】
/**** 用序列化和反序列化實現深克隆*/ package cn.sxt.prototype;import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Date;public class Test_0424_Client02 {public static void main(String[] args) throws Exception {Date date=new Date(1000000L);Sheep s1=new Sheep("羊一代",date);//要克隆出新羊,需要原型"羊",這就是原型"羊" System.out.println(s1);System.out.println("原型羊:"+s1.getBirthday());//Sheep s2=(Sheep)s1.clone();//新建一個對象,但不是通過new,而是直接調用原型"羊"的clone方法//深克隆方法之二:使用序列化和反序列化克隆一只羊ByteArrayOutputStream bos=new ByteArrayOutputStream();ObjectOutputStream oos=new ObjectOutputStream(bos);oos.writeObject(s1);byte[] buf=bos.toByteArray();ByteArrayInputStream bis=new ByteArrayInputStream(buf);ObjectInputStream ois=new ObjectInputStream(bis);Sheep s2=(Sheep)ois.readObject();System.out.println(s2);System.out.println("克隆羊:"+s2.getBirthday());//修改原型"羊"的出生日期,看看克隆羊的出生日期date.setTime(40000000L);System.out.println("修改原型羊的出生日期后:");System.out.println("原型羊:"+s1.getBirthday());System.out.println("克隆羊:"+s2.getBirthday());}}
?