1概述
1.1简介
原型模式指定创建对象的种类,并且通过拷贝这些原型创建新的对象,就是创建对象是不使用new,而是通过拷贝的方式创建对象。
1.2 原型模式的优点
性能好:原型模式是在内存二进制流中的拷贝,比new性能好很多。
逃避构造函数的约束:既是缺点也是优点,拷贝是构造函数不会执行。
1.3使用场景
资源优化
性能和安全要求的场景
一个对象多个修改者的场景
原型模式很少单独出现,一般和工厂方法模式一起出现,通过clone的方法创建一个新的对象,然后由工厂方法提供给调用者。Java中类实现CloneAble接口来使用。
1.4 注意事项
clone方法是浅拷贝,类的基本类型的成员变量与string类型是拷贝了一份,引用类型的不会重新创建对象,而是将引用指向了原来的变量的内存地址。因此,两个类公用一个引用对象。
如果想要深拷贝可以自行单独修改下clone方法,或者使用二进制流来操作对象,序列化对象再反序列化实现深拷贝。
另外,clone与对象final关键字有冲突的。如果使用clone方法不要在成员变量上使用final关键字。
2 简单实践
原型通用类图如下,比价简单,其实就是实现cloneable接口的一个类
创建一个电影类实现cloneable接口
**
* @author chiangtaol
* @date 2020-12-02
* @describe 电影
*/
@Data
@Builder
public class Movie implements Cloneable{
/**
* 标题
*/
private String title;
/**
* 内容
*/
private String content;
/**
* 演员
*/
private ArrayList<String> actors;
@Override
protected Movie clone(){
Movie movie = null;
try {
movie = (Movie) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("拷贝失败");
}
return movie;
}
}
再测试类中使用
/**
* @author chiangtaol
* @date 2020-12-02
* @describe
*/
class MovieTest {
@Test
public void test() throws Exception{
// 创建一个电影
Movie movie = Movie.builder().title("最后的进化").content("关于成长的...").actors(new ArrayList<>()).build();
movie.getActors().add("太一");
Movie clone = movie.clone();
clone.getActors().add("阿和");
System.out.println(movie.toString());
System.out.println(clone.toString());
}
}
执行结果如下:
Movie(title=最后的进化, content=关于成长的..., actors=[太一, 阿和]) Movie(title=最后的进化, content=关于成长的..., actors=[太一, 阿和])
虽然拷贝成功了,但是1.4说的浅拷贝的问题出来了,公用了一个私有成员变量,所以可以在movie修改下clone方法,
@Override
protected Movie clone(){
Movie movie = null;
try {
movie = (Movie) super.clone();
movie.setActors((ArrayList<String>) this.actors.clone());
} catch (CloneNotSupportedException e) {
System.out.println("拷贝失败");
}
return movie;
}
测试代码执行的结果就改为:
Movie(title=最后的进化, content=关于成长的..., actors=[太一]) Movie(title=最后的进化, content=关于成长的..., actors=[太一, 阿和])
这样深拷贝后两个对象就互相没有关系了。