原型模式
- 定义
原型模式(Prototype),用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象。[DP]
- 优缺点
优点:
- 拷贝对象省下了初始化对象的资源
- 复用被拷贝对象的一些共用的值
缺点:
- 需要在类中写clone方法,违法开闭原则
- 深拷贝时,需要让类的每一层都支持,复杂
- 逃避构造函数的约束
- 特点
- 分深浅拷贝
- 浅拷贝的对象不能有引用类型的属性,否则会出现新对象覆盖旧对象
- 被拷贝的类需要实现Cloneable类,使用this.clone()复制自己的对象并返回
- 结构
Prototype:原型父类
ConcretePrototype1:子原型类
ConcretePrototype2:子原型类

- 代码
例子:展示深拷贝和浅拷贝的区别,一个校牌类,一个学生类,校牌类持有一个学生类的对象,先创建一个三班 的张三校牌对象,然后拷贝一份,赋值为五班的李四,分别打印。
- 浅拷贝(注意:注释的代码不用看,是深浅拷贝替换的代码)
客户端调用类
/**
* @ Author :fonxi
* @ Date :2019/5/21 12:25
* @ Description:客户端调用类
*/
public class TestController {
public void print(){
SchoolCard p1 = new SchoolCard("三班");
p1.setStudent(new Student("张三"));
SchoolCard c1 = p1.Clone();
c1.setId("五班");
c1.getStudent().setName("李四");
System.out.println("p1="+p1.getId()+" name="+p1.getStudent().getName());
System.out.println("c1="+c1.getId()+" name="+c1.getStudent().getName());
}
}
校牌类,注释的代码不用看,是深拷贝的代码
/**
* @ Author :fonxi
* @ Date :2019/5/21 12:27
* @ Description:被拷贝的类,校牌类
*/
public class SchoolCard implements Cloneable{
private String id;
private Student student;
public SchoolCard(String id){
this.id = id;
}
// private SchoolCard(Student student){
// this.student = student.Clone();
// }
//
// public SchoolCard Clone(){
// SchoolCard concretePrototype1 = new SchoolCard(this.student);
// concretePrototype1.setId(this.getId());
// return concretePrototype1;
// }
public SchoolCard Clone(){
try {
return (SchoolCard) this.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
public void setStudent(Student student) {
this.student = student;
}
public Student getStudent() { return student; }
public void setId(String id) { this.id = id; }
public String getId() { return id; }
}
学生类
/**
* @ Author :fonxi
* @ Date :2019/5/21 13:13
* @ Description:被拷贝的类,学生类
*/
public class Student implements Cloneable{
// public Student Clone(){
// try {
// return (Student) this.clone();
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// }
// return null;
// }
public Student(String name){
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
输出结果:
p1=三班 name=李四 c1=五班 name=李四
明明是一个张三一个李四,但是都是李四,这里就是因为引用类型需要深拷贝,否则会覆盖前面的对象。
- 深拷贝(调用类不变)
校牌类修改
/**
* @ Author :fonxi
* @ Date :2019/5/21 12:27
* @ Description:被拷贝的类,校牌类
*/
public class SchoolCard implements Cloneable{
private String id;
private Student student;
public SchoolCard(String id){
this.id = id;
}
private SchoolCard(Student student){
this.student = student.Clone();
}
public SchoolCard Clone(){
SchoolCard concretePrototype1 = new SchoolCard(this.student);
concretePrototype1.setId(this.getId());
return concretePrototype1;
}
// public SchoolCard Clone(){
// try {
// return (SchoolCard) this.clone();
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// }
// return null;
// }
public void setStudent(Student student) { this.student = student; }
public Student getStudent() { return student; }
public void setId(String id) { this.id = id; }
public String getId() { return id; }
}
学生类修改
public class Student implements Cloneable{
public Student Clone(){
try {
return (Student) this.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
public Student(String name){
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
输出
p1=三班 name=张三 c1=五班 name=李四
perfect
- 总结
原型模式虽然可以带节省资源,方便对象的初始化,但是浅拷贝会有覆盖的问题,深拷贝需要一层一层的深入的修改,很复杂。需要根据场景慎重使用