设计模式-原型模式

1、原型模式简介

定义:属于创建型模式,用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象,这种方式创建对象非常高效,根本无须知道对象创建的细节

目标:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

解决问题:运行期建立和删除实例

优点:性能提高

    逃避构造函数的约束

缺点:需要为每一个类都配置一个 clone 方法

   clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。

   当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦

说明:原型模式的克隆分为两种,一种叫深克隆,一种叫浅克隆

2、浅克隆

定义:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址

实现:必须得实现实现 Cloneable 接口,只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化

//原型类
public class User {
    private String name;
    private int date;
    private int age;
    public void setName(String name) {
        this.name = name;
    }
    public void setDate(int date) {
        this.date = date;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getDate() {
        return date;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return getName()+"&&"+getDate()+"&&"+getAge();
    }
}

//具体原型类
public class CloneablePrototype implements Cloneable {
    private User user = new User();
    public CloneablePrototype(){
        user.setAge(25);
        user.setDate(1995);
        user.setName("CC");
        System.out.println("具体原型创建成功");
    }
    public Object clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功");
        return (CloneablePrototype)super.clone();
    }
    public User show(){
        return user;
    }

}

//测试方法
public static void main(String[] args) throws CloneNotSupportedException {
        CloneablePrototype cloneablePrototype1 = new CloneablePrototype();
        CloneablePrototype cloneablePrototype2 = (CloneablePrototype) cloneablePrototype1.clone();
        System.out.println("clone1:"+cloneablePrototype1.show().toString());
        System.out.println("clone2:"+cloneablePrototype2.show().toString());
        System.out.println(cloneablePrototype1 == cloneablePrototype2);
        System.out.println("===========================");
        cloneablePrototype2.show().setAge(30);
        System.out.println("clone1:"+cloneablePrototype1.show().toString());
        System.out.println("clone2:"+cloneablePrototype2.show().toString());
        System.out.println(cloneablePrototype1 == cloneablePrototype2);

}
//测试结果
具体原型创建成功
具体原型复制成功
clone1:CC&&1995&&25
clone2:CC&&1995&&25
false
===========================
clone1:CC&&1995&&30
clone2:CC&&1995&&30
false

3、深克隆

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

实现:实现 Serializable 接口,通过字节流来对数据进行复制

//原型类,实现Serializable接口
public class User extends Object implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int date;
    private int age;
    public void setName(String name) {
        this.name = name;
    }
    public void setDate(int date) {
        this.date = date;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getDate() {
        return date;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return getName()+"&&"+getDate()+"&&"+getAge();
    }
}

//具体原型类
public class SerializablePrototype implements Serializable {

    private User user = new User();
    public SerializablePrototype(){
        user.setAge(21);
        user.setName("NN");
        user.setDate(1998);
        System.out.println("具体原型创建成功");
    }
    public User show(){
        return user;
    }
    public SerializablePrototype sClone(SerializablePrototype serializablePrototype){
        try(ByteArrayOutputStream bOut = new ByteArrayOutputStream();
            ObjectOutputStream oOut = new ObjectOutputStream(bOut)){
            //oOut对象中指向写入数据存储的内存地址与bOut对象中指向数据存储的内存地址是一样的
            oOut.writeObject(serializablePrototype);
            try(ByteArrayInputStream bIn= new ByteArrayInputStream(bOut.toByteArray());
                ObjectInputStream oIn = new ObjectInputStream(bIn)){
                Object o = oIn.readObject();
                System.out.println("具体原型复制成功");
                return (SerializablePrototype) o;
            }catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  null;
    }
}

//测试方法
public static void main(String[] args) throws CloneNotSupportedException {
        SerializablePrototype s1 = new SerializablePrototype();
        SerializablePrototype s2 = s1.sClone(s1);
        System.out.println(s1.show().toString());
        System.out.println(s2.show().toString());
        System.out.println(s1 == s2);
        System.out.println("============================");
        s2.show().setName("QQ");
        System.out.println(s1.show().toString());
        System.out.println(s2.show().toString());
        System.out.println(s1 == s2);
}
//测试结果
具体原型创建成功
具体原型复制成功
NN&&1998&&21
NN&&1998&&21
false
============================
NN&&1998&&21
QQ&&1998&&21
false

由此可见,s2改变之后s1的不变,说明通过字节流将s1对象指向的实际内存地址中的数据复制到另一块实际内存中,s2指向的这块新的内存地址
posted @ 2020-09-29 16:45  CarBlack  阅读(128)  评论(0编辑  收藏  举报