创建型设计模式-Prototype原型设计模式实战

DBC 679 0
  • 原型设计模式Prototype
    • 是一种对象创建型模式,使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,主要用于创建重复的对象,同时又能保证性能
    • 工作原理是将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程
    • 应该是最简单的设计模式了,实现一个接口,重写一个方法即完成了原型模式

 

  • 核心组成
    • Prototype: 声明克隆方法的接口,是所有具体原型类的公共父类,Cloneable接口
    • ConcretePrototype : 具体原型类
    • Client: 让一个原型对象克隆自身从而创建一个新的对象

 

  • 应用场景
    • 创建新对象成本较大,新的对象可以通过原型模式对已有对象进行复制来获得
    • 如果系统要保存对象的状态,做备份使用
小例子——使用情况(比如对象太过于大,我们需要不断的set,非常的不方便!)
public class Person implements Cloneable {

    private String name;

    private int age;

    private List<String> list = new ArrayList<>();


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

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

    public Person(){
        System.out.println("构造函数调用");
    }

    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;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}
public class Client {

    public static void main(String [] args) throws CloneNotSupportedException {

        Person person1 = new Person();
        person1.setAge(10);
        person1.setName("小滴课堂-老王");
        person1.getList().add("aaa");



        Person person2 = person1.clone();
        person2.setName("Anna小姐姐");
        person2.getList().add("ccc");

        System.out.println("person1="+person1.getName()+", age="+person1.getAge());
        System.out.println("person2="+person2.getName()+", age="+person2.getAge());

    }
}
温馨提示

简单的对象复制可以成功,但是复杂的,比如说list的复制,居然会出现问题!往下面看,原因是什么?
创建型设计模式-Prototype原型设计模式实战插图可以看到,A对象和B对象居然数组是一样的!

其实是浅拷贝、深拷贝的区别!

遗留问题:

  • 通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的
  • 浅拷贝实现 Cloneable,深拷贝是通过实现 Serializable 读取二进制流
  • 拓展
浅拷贝

如果原型对象的成员变量是基本数据类型(int、double、byte、boolean、char等),将复制一份给克隆对象;
如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址

通过覆盖Object类的clone()方法可以实现浅克隆

深拷贝

无论原型对象的成员变量是基本数据类型还是引用类型,都将复制一份给克隆对象,如果需要实现深克隆,可以通过序列化(Serializable)等方式来实现

  • 原型模式是内存二进制流的拷贝,比new对象性能高很多,使用的时候记得注意是选择浅拷贝还是深拷贝
  • 优点
    • 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,可以提高新实例的创建效率
    • 可辅助实现撤销操作,使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用恢复到历史状态

 

  • 缺点
    • 需要为每一个类配备一个克隆方法,对已有的类进行改造时,需要修改源代码,违背了“开闭原则”
    • 在实现深克隆时需要编写较为复杂的代码,且当对象之间存在多重的嵌套引用时,需要对每一层对象对应的类都必须支持深克隆
修改小例子
public class Client {

    public static void main(String [] args) throws CloneNotSupportedException {


        Person person1 = new Person();
        person1.setAge(10);
        person1.setName("小滴课堂-老王");
        person1.getList().add("aaa");


        //浅拷贝
        //Person person2 =  person1.clone();

        //深拷贝
        Person person2 =  (Person) person1.deepClone();
        person2.setName("Anna小姐姐");
        person2.getList().add("ccc");

        System.out.println("person1="+person1);
        System.out.println("person2="+person2);
    }
}
public class Person implements Cloneable, Serializable {

    private String name;

    private int age;

    private List<String> list = new ArrayList<>();

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", list=" + list +
                '}';
    }

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

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

    public Person() {
        System.out.println("构造函数调用");
    }

    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;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }


    /**
     * 深拷贝
     * @return
     */
    public Object deepClone() {

        try {
            //输出 序列化
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);

            //输入 反序列化
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Person copyObj = (Person) ois.readObject();

            return copyObj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }


    }


}
控制台输出创建型设计模式-Prototype原型设计模式实战插图2

发表评论 取消回复
表情 图片 链接 代码

分享