design pattern · 2020-01-27 0

Java设计模式-原型模式

一、概述

原型模式是指用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。原型模式是一种创建型的设计模式,分为深克隆和浅克隆。

通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝他们自己来实施创建,即:对象.clone()

二、角色

抽象原型:它是声明克隆方法的接口,是所有具体原型类的公共父类,它可以是接口,抽象类甚至是一个具体的实现类

具体原型:它实现了抽象原型类中声明的克隆方法,在克隆方法中返回一个自己的克隆对象

客户类:在客户类中,使用原型对象只需要通过工厂方式创建或者直接new(实例化一个)原型对象,然后通过原型对象的克隆方法就能获得多个相同的对象。

三、栗子

1.浅克隆

1) Parent与Child类

public class Parent implements Cloneable {

    private String name;
    private Child child;

    public Parent(String name, Child child) {
        this.name = name;
        this.child = child;
    }

    public String getName() {
        return name;
    }

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

    public Child getChild() {
        return child;
    }

    public void setChild(Child child) {
        this.child = child;
    }

    @Override
    public String toString() {
        return "Parent{" +
                "name='" + name + ''' +
                ", child=" + child +
                '}';
    }

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

class Child implements Cloneable {

    private String name;

    public Child(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Child{" +
                "name='" + name + ''' +
                '}';
    }

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

2) 测试

@Test
public void testWeakClone() {
    Child child = new Child("child");
    Parent parent = new Parent("parent", child);

    Parent parentClone = (Parent) parent.clone();
    parentClone.getChild().setName("childClone");

    System.out.println(parent);
    System.out.println(parentClone);
}

3) 结果

Parent {name='parent', child=Child{name='childClone'}}
Parent {name='parent', child=Child{name='childClone'}}

2.深克隆

1) Parent与Child类

public class Parent implements Cloneable, Serializable {

    private String name;
    private Child child;

    public Parent(String name, Child child) {
        this.name = name;
        this.child = child;
    }

    public String getName() {
        return name;
    }

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

    public Child getChild() {
        return child;
    }

    public void setChild(Child child) {
        this.child = child;
    }

    @Override
    public String toString() {
        return "Parent{" +
                "name='" + name + ''' +
                ", child=" + child +
                '}';
    }

    // 深克隆 - 方式1 使用clone方法
    @Override
    protected Object clone() {
        try {
            Parent parentClone = (Parent) super.clone();
            // 引用类型克隆
            parentClone.child = (Child) this.child.clone();
            return parentClone;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 深克隆 - 方式2 通过对象的序列化实现(推荐)
    public Object deepClone() {
        // 创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            // 序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); // 当前这个对象以对象流的方式输出
            // 反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            Parent parentClone = (Parent)ois.readObject();
            return parentClone;
        } catch (Exception e) {
            return null;
        } finally {
            // 关闭流
            try {
                ois.close();
                bis.close();
                oos.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

class Child implements Cloneable, Serializable {

    private String name;

    public Child(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Child{" +
                "name='" + name + ''' +
                '}';
    }

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

2) 测试

@Test
public void testDeepClone1() {
    Child child = new Child("child");
    Parent parent = new Parent("parent", child);

    Parent parentClone = (Parent) parent.clone();
    parentClone.getChild().setName("childClone");

    System.out.println(parent);
    System.out.println(parentClone);
}

@Test
public void testDeepClone2() {
    Child child = new Child("child");
    Parent parent = new Parent("parent", child);

    Parent parentClone = (Parent) parent.deepClone();
    parentClone.getChild().setName("childClone");

    System.out.println(parent);
    System.out.println(parentClone);
}

3) 结果

Parent {name='parent', child=Child{name='child'}}
Parent {name='parent', child=Child{name='childClone'}}

四、浅克隆与深克隆

1.浅克隆

1) 对于数据类型是基本数据类型的成员变量,浅克隆会直接进行值传递,也就是将该属性值复制一份给新的对象

2) 对于数据类型是引用数据类型的变量,那么浅克隆会进行引用传递,只是将成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。

3) 浅克隆是使用默认的clone()方法来实现

2.深克隆

1) 复制对象的所有基本类型的成员变量

2) 为所有引用数据类型的成员变量申请存储空间,并复制每个引用类型成员变量所引用的对象,直到该对象可达的所有对象

3) 深克隆实现方式1:重写clone方法来实现深克隆

4) 深克隆实现方式2:通过对象序列化实现深克隆(推荐)