设计模式-原型模式
原型模式
- 定义
原型模式(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
- 总结
原型模式虽然可以带节省资源,方便对象的初始化,但是浅拷贝会有覆盖的问题,深拷贝需要一层一层的深入的修改,很复杂。需要根据场景慎重使用