Copy小王子-原型模式

概述

原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的

类图

在这里插入图片描述

原型模式也是一种很简单的模式,其核心就是使用了对象的克隆

代码实现

public class Classes {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Student implements Cloneable{
    private String name;
    private int age;
    private Classes classes;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Classes getClasses() {
        return classes;
    }

    public void setClasses(Classes classes) {
        this.classes = classes;
    }

    @Override
    protected Student clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }

    @Override
    public String toString() {
        return "Student[name=" + name + ",age=" + age + ",class=" + classes.getName() + "]";
    }
}

public class Client {
    public static void main(String[] args){
        Student stu1 = new Student();
        stu1.setName("stu1");
        stu1.setAge(10);
        Classes classes = new Classes();
        classes.setName("class1");
        stu1.setClasses(classes);

        Student stu2 = stu1.clone();
        stu2.setName("stu2");

        System.out.println(stu1.toString());
        System.out.println(stu2.toString());
    }
}

优缺点

优点

  • 性能优良。原型模式是在内存中进行二进制流拷贝,要比直接new一个对象的性能要好很多
  • 逃避构造函数的约束。原型模式直接在内存中克隆对象,不调用构造函数(也是缺点)

缺点

  • 必须实现 Cloneable 接口
  • 当类的内部结构比较复杂时,实现起来比较复杂

使用场景

  • 资源优化场景,当类初始化需要消化非常多的资源时,可以考虑使用原型模式
  • 性能和安全要求的场景,过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
  • 一个对象有多个使用者进行修改时,可以考虑将对象拷贝多份供不同的调用者使用

注意事项

  • 由于原型模式是直接在内存中拷贝对象,对象的构造函数不会被执行
public class People implements Cloneable{

    public People(){
        System.out.println("构造函数被执行了");
    }

    private String name;
    private ArrayList<String> list;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ArrayList<String> getList() {
        return list;
    }

    public void setList(ArrayList<String> list) {
        this.list = list;
    }

    @Override
    protected People clone(){
        People people = null;
        try {
            people = (People) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return people;
    }

    @Override
    public String toString() {
        return "People[name=" + name + ",list=" + list.toString() + "]";
    }
}

public class Client {
    public static void main(String[] args){
        People p1 = new People();
        p1.setName("p1");
        People p2 = p1.clone();
    }
}

输出结果:
构造函数被执行了

---------------------
从输出结果可以看出来,调用clone方法时没有执行构造方法
  • 要注意浅拷贝风险
public class Client {
    public static void main(String[] args){
        People p1 = new People();
        List<String> list = new ArrayList<String>();
        p1.setName("p1");
        list.add("aaa");
        p1.setList(list);
        People p2 = p1.clone();
        p2.setName("p2");
        p2.getList().add("bbb");
        System.out.println(p1.toString());
        System.out.println(p2.toString());
    }
}
输出结果:
构造函数被执行了
People[name=p1,list=[aaa, bbb]]
People[name=p2,list=[aaa, bbb]]
   

从输出结果可以看出来,clone后People内部的list并没有被clone出来,还是指向同一个list,这就是浅拷贝。
如果想实现深拷贝,则需要修改一下clone方法

 protected People clone(){
        People people = null;
        try {
            people = (People) super.clone();
            people.list = (ArrayList<String>) this.list.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return people;
    }

总结一下

  • 原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
  • 原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的
  • 原型模式的优点:
    • 性能优良。原型模式是在内存中进行二进制流拷贝,要比直接new一个对象的性能要好很多
    • 逃避构造函数的约束。原型模式直接在内存中克隆对象,不调用构造函数(也是缺点)
  • 原型模式的缺点:
    • 必须实现 Cloneable 接口
    • 当类的内部结构比较复杂时,实现起来比较复杂
  • 原型模式的使用场景:
    • 资源优化场景,当类初始化需要消化非常多的资源时,可以考虑使用原型模式
    • 性能和安全要求的场景,过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
    • 一个对象有多个使用者进行修改时,可以考虑将对象拷贝多份供不同的调用者使用
  • 注意事项
    • 由于原型模式是直接在内存中拷贝对象,对象的构造函数不会被执行
    • 要注意浅拷贝风险

欢迎您关注Java天堂公众号,专注于分享Java相关技
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/pzjtian/article/details/104291479