Java设计模式-Prototype原型设计模式(浅拷贝和深拷贝)

浅拷贝

简介

原型设计模式Prototype

1、是⼀种对象创建型模式,使⽤原型实例指定创建对象的种类,并且通过拷⻉这些原型创建新的对象,主要⽤于创建重复的对象,同时⼜能保证性能
2、⼯作原理是将⼀个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷⻉⾃⼰来实现创建过程
3、应该是最简单的设计模式了,实现⼀个接⼝,重写⼀个⽅法即完成了原型模式

核心组成

Prototype: 声明克隆⽅法的接⼝,是所有具体原型类的公共⽗类,Cloneable接⼝
ConcretePrototype : 具体原型类
Client: 让⼀个原型对象克隆⾃身从⽽创建⼀个新的对象

应用场景

1、创建新对象成本较⼤,新的对象可以通过原型模式对已有对象进⾏复制来获得
2、如果系统要保存对象的状态,做备份使⽤

demo
创建对象

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

创建client

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("李四");
        person2.getList().add("ccc");

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

    }
}

结果展示
执行时可以看一下list的内存地址(两个list地址是一样的)

构造函数调用
person1=张三,age=10,list=[aaa,ccc]
persion2=李四,age=10,list=[aaa,ccc]

深拷贝

遗留问题

1、通过对⼀个类进⾏实例化来构造新对象不同的是,原型模式是通过拷⻉⼀个现有对象⽣成新对象的
2、浅拷⻉实现 Cloneable,深拷⻉是通过实现Serializable 读取⼆进制流

浅拷贝和深拷贝介绍
浅拷贝

1、如果原型对象的成员变量是基本数据类型(intdoublebytebooleanchar等),将复制⼀份给克隆对象;
2、如果原型对象的成员变量是引⽤类型,则将引⽤对象的地址复制⼀份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址
3、通过覆盖Object类的clone()⽅法可以实现浅克隆

深拷贝

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

优缺点
优点

1、原型模式是内存⼆进制流的拷⻉,⽐new对象性能⾼很多,使⽤的时候记得注意是选择浅拷⻉还是深拷⻉
2、当创建新的对象实例较为复杂时,使⽤原型模式可以简化对象的创建过程,可以提⾼新实例的创建效率
3、可辅助实现撤销操作,使⽤深克隆的⽅式保存对象的状态,使⽤原型模式将对象复制⼀份并将其状态保存起来,以便在需要的时候使⽤恢复到历史状态

缺点

1、需要为每⼀个类配备⼀个克隆⽅法,对已有的类进⾏改造时,需要修改源代码,违背了“开闭原则”
2、在实现深克隆时需要编写较为复杂的代码,且当对象之间存在多重的嵌套引⽤时,需要对每⼀层对象对应的类都必须⽀持深克隆

demo

public class Person implements Cloneable, Serializable {
    
    

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


    /**
     * 深拷贝
     * @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;
        }
    }
}

创建client调用

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("李四");
        person2.getList().add("ccc");

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

    }
}

结果展示
执行时可以看一下list的内存地址(两个list地址是不一样的)

构造函数调用
person1=张三,age=10,list=[aaa]
persion2=李四,age=10,list=[aaa,ccc]

猜你喜欢

转载自blog.csdn.net/csdn_mycsdn/article/details/129114213