原型模式
- 有一只羊,名tom,年龄1,颜色白,创建10只完全一样的羊
- prototype,用原型实例指定创建对象的类型,通过拷贝这些原型,创建新的对象,是一种
创建型设计模式,允许一个对象在创建另一个可定制的对象
- 原理,通过将一个原型对象传给要发动创建的对象,这个发动创建的对象,通过请求原型对象拷贝它们自己来实施创建对象
传统思路

Sheep sheep = new Sheep("tom", "白色", 1);
Sheep sheep1 = new Sheep(sheep.getName(), sheep.getColor(), sheep.getAge());
Sheep sheep2 = new Sheep(sheep.getName(), sheep.getColor(), sheep.getAge());
Sheep sheep3 = new Sheep(sheep.getName(), sheep.getColor(), sheep.getAge());
Sheep sheep4 = new Sheep(sheep.getName(), sheep.getColor(), sheep.getAge());
- 创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂,效率较低
- 总是需要重新初始化对象,不能动态地获取对象运行时的状态
- 改进,java中Object类是所有类的根类,其中
clone()方法,可以将java对象复制一遍,但是需要实现Cloneable接口,让该类能够复制且具有复制的能力
实现Cloneable接口
- 为对象增加属性时,无需修改复制对象的代码
- 默认浅拷贝
public class Sheep implements Cloneable {
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (Exception e) {
e.printStackTrace();
}
return sheep;
}
}
Sheep sheep = new Sheep("tom","white",1)
Sheep sheep1 = (Sheep) sheep.clone()
Sheep sheep2 = (Sheep) sheep.clone()
Sheep sheep3 = (Sheep) sheep.clone()
spring中的原型模式
<bean id="id01" class="com.java.spring.bean.Monster" scope="prototype"/>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml")
// 获取monster[通过id获取monster]
Object bean = applicationContext.getBean("id01")
System.out.println("bean" + bean)
Object bean2 = applicationContext.getBean("id01")
System.out.println("bean2" + bean2)
System.out.println(bean == bean2)
public Object getBean(String name) throws BeansException {
this.assertBeanFactoryActive();
return this.getBeanFactory().getBean(name);
}
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
- 检查是以什么方式创建

- mbd

- 调用createBean

浅拷贝和深拷贝
- 如果属性是对象,在克隆时,没有真正被复制,只是复制了引用
Sheep sheep = new Sheep("tom","white",1)
sheep.friend = new Sheep("jack","black",2)
Sheep sheep1 = (Sheep) sheep.clone()
System.out.println(sheep.friend.hashCode())
System.out.println(sheep1.friend.hashCode())
浅拷贝
- 对于数据类型是
基本数据类型的成员变量,浅拷贝会直接进行值传递,将属性值复制一份
- 对于数据类型是
引用数据类型的成员变量,数组、类的对象,浅拷贝会进行引用传递,只是将该成员变量的引用值(内存地址)复制一份,实际上两个对象的引用数据类型的成员变量都指向同一块区域,一变均变
深拷贝
- 复制对象的所有基本数据类型的成员变量值
- 为所有引用数据类型的成员变量申请存储空间,并复制
每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象
- 对象进行深拷贝,要对整个对象进行拷贝
- 实现方式
- 重写
clone
- 对象序列化
重写clone实现
DeepCloneableTarget 也需要实现clone,克隆其中的成员变量
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null
//完成对基本数据类型和String的克隆
deep = super.clone()
//对引用类型进行处理
DeepProtoType deepProtoType = (DeepProtoType) deep
deepProtoType.dct = (DeepCloneableTarget) dct.clone()
return deepProtoType
}
序列化
//序列化
public Object deepClone() {
//创建流对象
ByteArrayOutputStream bos = null
ObjectOutputStream oos = null
ByteArrayInputStream bis = null
ObjectInputStream ois = null
try {
//序列化
bos = new ByteArrayOutputStream()
oos = new ObjectOutputStream(bos)
//当前这个对象,以对象流的形式输出
oos.writeObject(this)
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray())
ois = new ObjectInputStream(bis)
DeepProtoType dpt = (DeepProtoType) ois.readObject()
return dpt
} catch (Exception e) {
e.printStackTrace()
return null
} finally {
try {
if (bos != null) bos.close()
if (oos != null) oos.close()
if (bis != null) bis.close()
if (ois != null) ois.close()
} catch (Exception e2) {
e2.printStackTrace()
}
}
}
小结
- 简化复制对象的创建过程,不用重新初始化对象,动态获取对象运行时的状态
- 如果原始对象发生变化,其他克隆对象也会发生相应的变化,无需修改代码
- 深拷贝需要比较复杂的处理,分别处理引用数据类型
- 原型模式需要为每个类,配备一个克隆方法,对已有的类进行改造,需要修改其源代码,违反了ocp原则
建造者模式
- 需要建房子,打桩、砌墙、封顶
- 房子有各式各样,过程一样,但是要求不同
- Builder Pattern,生成器模式,对象构建模式
- 将复杂对象的建造过程抽象出来,使这个抽象过程的
不同实现方法可以构造出不同属性的对象
- 四个角色
- product 产品角色,具体的产品对象
- Builder 抽象建造者,创建一个product对象的各个部件指定的接口/抽象类
- ConcreteBuilder 具体建造者,实现接口,构建和装配各个部件
- Director 指挥者,一个使用builder接口的对象,用于创建一个复杂的对象。一是,隔离了客户和对象的生产过程;二是,负责控制产品对象的生产过程
传统思维

- 没有设计缓存层,将产品和创建产品的过程封装在一起了,耦合性增强
- 将产品和产品建造过程进行解耦
改进
- 建造者类图

- 以造房子为例

- 产品,规范化,不同的产品区别在于属性值不同
public class House {
private String basic;
private String wall;
private String roofed;
}
- HouseBuilder,规范制造的部分,具体实现交给子类,都需要建造
public abstract class HouseBuilder {
protected House house = new House();
public abstract void buildBasic();
public abstract void buildWalls();
public abstract void roofed();
public House build() {
return house;
}
}
public class CommonHouse extends HouseBuilder{
@Override
public void buildBasic() {
house.setBasic("common");
System.out.println("CommonHouse buildBasic");
}
@Override
public void buildWalls() {
house.setWall("common");
System.out.println("CommonHouse buildWalls");
}
@Override
public void roofed() {
house.setRoofed("common");
System.out.println("CommonHouse roofed");
}
}
- HouseDirector,指挥者,不同的指挥者,过程顺序不同
public class HouseDirector {
HouseBuilder hb = null;
public HouseDirector(HouseBuilder hb) {
this.hb = hb;
}
public void setHb(HouseBuilder hb) {
this.hb = hb;
}
public House contructHouse() {
hb.buildBasic();
hb.buildWalls();
hb.roofed();
return hb.build();
}
}
StringBuilder源码
- 产品是
String或者Buffer
StringBuilder继承AbstractStringBuilder,既充当了指挥者,又充当了建造者,建造方法的实现是由AbstractStringBuilder完成的

AbstractStringBuilder实现Appendable的接口方法,实现了多个append方法,作为建造者,只是不能实例化,被不同的指挥者调用

Appendable定义了多个append方法,作为抽象建造者

小结
- 每一个具体建造者都相对独立,与其他建造者无关,用户使用不同的具体建造者,得到不同的产品
- 更加精细化地控制产品的创建过程
- 新增加的具体建造者无须修改原有类库代码,符合开闭原则
- 创建的产品需要
有较多的共同点,其组成部分相似
- 抽象工厂模式和建造者模式
- 抽象工厂模式,实现对产品家族的创建,是一系列的产品,具有不同分类维度的产品组合,不需要关心构建过程,只关系什么产品通过什么工厂生产
- 建造者模式,要求按照指定的蓝图建造产品,通过组装零配件而产生一个新产品