[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());
    }

}

 

posted @ 2019-04-22 13:42  ID长安忆  阅读(268)  评论(0)    收藏  举报