一、建造者模式

本质:分离了对象子组件的单独构造(由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());
} }

[19/04/24-星期三] GOF23_创建型模式(建造者模式、原型模式)的更多相关文章

  1. NET设计模式 第二部分 创建型模式(5):原型模式(Prototype Pattern)

    原型模式(Prototype Pattern) ——.NET设计模式系列之六 Terrylee,2006年1月 概述 在软件系统中,有时候面临的产品类是动态变化的,而且这个产品类具有一定的等级结构.这 ...

  2. [19/04/22-星期一] GOF23_创建型模式(单例模式)

    一.概念 <Design Patterns: Elements of Reusable Object-Oriented Software>(即后述<设计模式>一书),由 Eri ...

  3. [19/04/23-星期二] GOF23_创建型模式(工厂模式、抽象工厂模式)

    一.工厂模式(分为:简单工厂模式.工厂方法模式.抽象工厂模式) 实现了创建者和调用者的分离 核心本质:1.实例化对象,用工厂方法代替new操作:2.将选择实现类.创建对象统一管理和控制,从而将调用者跟 ...

  4. 《JAVA与模式》之原型模式(转载)

    原型模式其实就是java的拷贝机制 原文出处:http://blog.csdn.net/zhengzhb/article/details/7393528   定义:用原型实例指定创建对象的种类,并通过 ...

  5. 《JAVA与模式》之原型模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...

  6. js17---创建对象:构造函数式和原型组合模式、动态原型模式、稳妥构造函数式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  7. [19/04/28-星期日] GOF23_结构型模式(享元模式)

    一.享元模式(FlyWeight,轻量级) [共享类与非共享类] /*** *FlyweightFactory享元工厂类: 创建并管理享元对象,享元池一般设计成键值对 */ package cn.sx ...

  8. Android中的创建型模式总结

    共5种,单例模式.工厂方法模式.抽象工厂模式.建造者模式.原型模式 单例模式 定义:确保某一个类的实例只有一个,而且向其他类提供这个实例. 单例模式的使用场景:某个类的创建需要消耗大量资源,new一个 ...

  9. C#设计模式之六原型模式(Prototype)【创建型】

    一.引言 在开始今天的文章之前先说明一点,欢迎大家来指正.很多人说原型设计模式会节省机器内存,他们说是拷贝出来的对象,这些对象其实都是原型的复制,不会使用内存.我认为这是不对的,因为拷贝出来的每一个对 ...

随机推荐

  1. 计算细胞数【BFS】

    问题描述 一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数. 输入格式 2行:第1行为两个整数 mm, nn, 代表矩阵 ...

  2. sprintf 格式化字符串

    好久没写博客了,又遇到自己觉得很傻的问题,格式化字符串还要找下 定义和用法 sprintf() 函数把格式化的字符串写入变量中. arg1.arg2.++ 参数将被插入到主字符串中的百分号(%)符号处 ...

  3. 分析解决 spring quartz 中出现的执行两次问题

    1. 问题描述 在开发询盘功能时,遇到一个需求,就是后台定时任务执行用电施工业务的工单下发. 使用的技术是 spring quartz,因为其他应用有先例,配置quartz 完成后,先写了一个 hel ...

  4. 用手机管理及维护MySQL,Oracle等数据库

    现在移动办公的情况及需求越来越多,平时MySQL,Oracle,SQLServer等数据库的管理都要通过客户端工具操作,现在有一款基于web网页的软件:TreeSoft数据库管理系统,在服务器布署一套 ...

  5. docker启动容器报错:IPv4 forwarding is disabled. Networking will not work

    报这个错误会导致宿主机以外的pc 访问不了容器 按照网上的解决办法: 在/usr/lib/sysctl.d/00-system.conf文件后加net.ipv4.ip_forward=1 即可 然后重 ...

  6. 20个实用便捷的CSS3工具、库及实例

    编者按:坊间传闻,有本CSS的高手炼成秘籍在江湖失传已久,书中所载,多为最新的惊人技术与实例示范,是为集大成者,一旦学成,代码效率猛增,功力提升数倍,今日偶获,不敢怠慢,赶紧发到优设,望人人受益.说人 ...

  7. Ubuntu16.04 下安装tomcat

    有两种常用方法: 一.通过 apt-get 命令进行在线安装(会自动配置好环境变量和服务) 二.通过下载并解压 .tar.gz 包进行手动安装(需要手动配置环境变量) 一.通过 apt-get 命令进 ...

  8. 如何实现监听 console.log

    var lastLog; console.oldLog = console.log; console.log = function(str) { console.oldLog(str); lastLo ...

  9. 面向对象第四章(封装、static)

    1.package: 1)作用:避免类名的冲突 2)包名可以有层次结构 3)类的全称: 包名.类名,同包中的类不能同名 4)建议:包名所有字母都小写 import: 1)同包中的类可以直接访问, 不同 ...

  10. Linux时间同步+国内常用的NTP服务器地址

    当Linux服务需要时间戳的时候,时间同步就显得十分重要.这里介绍下,最近我使用的一个同步命令. # ntpdate s1a.time.edu.cn 国内常用的NTP地址 210.72.145.44 ...