[19/04/24-星期三] GOF23_创建型模式(建造者模式、原型模式)
一、建造者模式
本质:分离了对象子组件的单独构造(由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()); } }

浙公网安备 33010602011771号