设计模式之——原型模式

原型模式

原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。重点是对象的拷贝

适用场景
1、类初始化消耗资源较多。
2、new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
3、构造函数比较复杂。
4、循环体中生产大量对象时。

简单克隆(浅克隆)

public interface Prototype{
    Prototype clone();
}

创建克隆对象

public class ConcretePrototype implements Prototype {
    private int age;
    private String name;
    private List hobbies;
    //get、set方法省略
    @Override
    public ConcretePrototype clone() {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setAge(this.age);
        concretePrototype.setName(this.name);
        concretePrototype.setHobbies(this.hobbies);
        return concretePrototype;
    }
}
public class Client {
    private Prototype prototype;
    public Client(Prototype prototype){
        this.prototype = prototype;
    }
    public Prototype startClone(Prototype concretePrototype){
        return (Prototype)concretePrototype.clone();
    }
}

测试

public class PrototypeTest {
    public static void main(String[] args) {
        // 创建一个具体的需要克隆的对象
        ConcretePrototype concretePrototype = new ConcretePrototype();
        // 填充属性,方便测试
        concretePrototype.setAge(30);
        concretePrototype.setName("prototype");
        List hobbies = new ArrayList();
        concretePrototype.setHobbies(hobbies);
        System.out.println(concretePrototype);
        // 创建 Client 对象,准备开始克隆
        Client client = new Client(concretePrototype);
        ConcretePrototype concretePrototypeClone = (ConcretePrototype)
client.startClone(concretePrototype);
        System.out.println(concretePrototypeClone);
        System.out.println("克隆对象中的引用类型地址值:" +     concretePrototypeClone.getHobbies());
        System.out.println("原对象中的引用类型地址值:" + concretePrototype.getHobbies());
        System.out.println("对象地址比较:"+(concretePrototypeClone.getHobbies() ==
        concretePrototype.getHobbies()));
    }
}

(https://upload-images.jianshu.io/upload_images/19649934-64d9988d822ad553.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

结论:
浅克隆只是完整复制了值类型数据,没有赋值引用对象。换言之,所有的引用对象仍然指向原来的对象,复制的不是值,而是引用的地址。

深克隆

创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。

代码演示:

public class Professor implements Cloneable {
    private String name;
    private Integer age;
    public Professor(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public Object clone() {

        Object o = null;
        try {
            o = super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
        return o;
    }

}

public class Student implements Cloneable {
    private String name;
    private Integer age;
    private Professor professor;
    public Student(String name, Integer age, Professor professor) {
        this.name = name;
        this.age = age;
        this.professor = professor;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public Professor getProfessor() {
        return professor;
    }

    public void setProfessor(Professor professor) {
        this.professor = professor;
    }

    public Object clone() {

        Student o = null;
        try {
            o = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
        o.professor = (Professor) professor.clone();
        return o;
    }
}

测试:
public class DeepCloneT {
    public static void main(String[] args) {
        Professor p = new Professor("wangwu", 50);
        Student s1 = new Student("xiaoming", 20, p);
        Student s2 = (Student) s1.clone();
        s2.getProfessor().setName("xiaowangwu");
        s2.getProfessor().setAge(40);
        System.out.println("name=" + s1.getProfessor().getName()
                + "," + "age=" + s1.getProfessor().getAge());

        System.out.println("name=" + s2.getProfessor().getName()
                + "," + "age=" + s2.getProfessor().getAge());
    }
}

输出结果:
name=wangwu,age=50
name=xiaowangwu,age=40

问题:克隆破坏单例模式?
如果我们克隆的目标的对象是单例对象,那意味着,深克隆就会破坏单例。实际上防止克隆破坏单例解决思路非常简单,禁止深克隆便可。

要么你我们的单例类不实现Cloneable 接口;要么我们重写 clone()方法,在 clone 方法中返回单例对象即可。

具体实现

@Override
protected Object clone() throws CloneNotSupportedException {
    return INSTANCE;
}

你可能感兴趣的:(设计模式之——原型模式)