原型模式
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
说简单点,就是我们程序员的CV大法了
既然是复制一个对象,那么直接new一个然后赋值不就完skr了吗,为什么还要搞出个原型模式这个幺蛾子呢
图样图森破!
如果一个对象有十几二十个属性,如果new出来再一一赋值,岂不是很难受?所以原型模式就应运而生了。
如何实现
Cloneable接口和clone方法
Prototype模式中实现起来最困难的地方就是内存复制操作,所幸在Java中提供了clone()方法替我们做了绝大部分事情。
两个概念
浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝。
深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。
三个角色:
Prototype:抽象原型类。声明克隆自身的接口。
ConcretePrototype:具体原型类。实现克隆的具体操作。
Client:客户类。让一个原型克隆自身,从而获得一个新的对象。
一般来说,抽象原型类不是必要的,可以直接声明具体的原型类来替代 (抽象原型类+实现抽象原型接口的具体原型类) 的组合
实例
浅拷贝
声明具体原型类,并实现浅拷贝的操作
public class Sheep implements Cloneable,Serializable {
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone(); //直接调用object对象的clone()方法!
return obj;
}
//省略getter和setter方法
//省略构造方法
}
客户端调用
浅拷贝生成的s2,改变name后原来的s1也跟着变了,说明是指向同一个对象的
深拷贝
声明具体原型类,并实现浅拷贝的操作
//测试深复制
public class Sheep2 implements Cloneable { //1997,英国的克隆羊,多利!
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone(); //直接调用object对象的clone()方法!
//添加如下代码实现深复制(deep Clone)
Sheep2 s = (Sheep2) obj;
s.birthday = (Date) this.birthday.clone(); //把属性也进行克隆!
return obj;
}
// 省略getter 和setter方法
// 省略构造方法
}
客户端调用
public class Client2 {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(12312321331L);
Sheep2 s1 = new Sheep2("少利",date);
Sheep2 s2 = (Sheep2) s1.clone(); //实现深复制。s2对象的birthday是一个新对象!
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
date.setTime(23432432423L);
System.out.println(s1.getBirthday());
s2.setSname("多利");
System.out.println(s2);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
}
}
拷贝生成的s2,当改变其name时,s1未改变,说明他们指向不同的对象
开发中的应用场景:
原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
spring中bean的创建实际就是两种:单例模式和原型模式。(当然,原型模式需要和工厂模式搭配起来)