设计模式-原型模式

原型模式

  • 定义

原型模式(Prototype),用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象。[DP]


 

  • 优缺点

优点:

  1. 拷贝对象省下了初始化对象的资源
  2. 复用被拷贝对象的一些共用的值

缺点:

  1. 需要在类中写clone方法,违法开闭原则
  2. 深拷贝时,需要让类的每一层都支持,复杂
  3. 逃避构造函数的约束

 

  • 特点
  1. 分深浅拷贝
  2. 浅拷贝的对象不能有引用类型的属性,否则会出现新对象覆盖旧对象
  3. 被拷贝的类需要实现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


 

  • 总结

原型模式虽然可以带节省资源,方便对象的初始化,但是浅拷贝会有覆盖的问题,深拷贝需要一层一层的深入的修改,很复杂。需要根据场景慎重使用

posted @ 2019-05-22 23:19  fonxi  阅读(93)  评论(0编辑  收藏  举报