设计模式:007_原型模式

56 阅读4分钟

原型模式

原型模式,指将一个对象作为原型,对其进行复制、克隆,产生一个和原对象属性相同的新对象。

普通模式复制对象

调用对象的 get/set 方法设置属性

public class Sheep {
    private String name;
    private int age;

    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
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Sheep sheep = new Sheep();
sheep.setName("Dolly");
sheep.setAge(1);

Sheep sheep2 = new Sheep();
sheep2.setName(sheep.getName());
sheep2.setAge(sheep.getAge());

// 各属性相同,但对象的地址不同
System.out.println("sheep:" + sheep);
System.out.println("sheep2:" + sheep2);
System.out.println("sheep:" + sheep.hashCode());
System.out.println("sheep2:" + sheep2.hashCode());

原型模式复制对象

public class Sheep implements Cloneable {
    private String name;
    private int age;

    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
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sheep;
    }
}
Sheep sheep = new Sheep();
sheep.setName("Dolly");
sheep.setAge(1);

Sheep sheep2 = (Sheep) sheep.clone();

// 各属性相同,但对象的地址不同
System.out.println("sheep:" + sheep);
System.out.println("sheep2:" + sheep2);
System.out.println("sheep:" + sheep.hashCode());
System.out.println("sheep2:" + sheep2.hashCode());

浅拷贝

基本数据类型

当成员变量是基本数据类型,浅拷贝会直接进行值传递,将该属性值复制一份给新对象。

引用数据类型

当成员变量是引用数据类型,浅拷贝会进行引用传递,将该属性的引用地址复制一份给新对象。 此时,新对象和原型对象的成员变量指向同一个实例,在一个对象中修改这个成员变量,另一个对象也会受到影响。

浅拷贝使用默认的 clone() 方法实现。

public class Dog implements Cloneable {
    private String name;
    private int age;

    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
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

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

public class Sheep implements Cloneable {
    private String name;
    private int age;
    private Dog friend;

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

    public Dog getFriend() {
        return friend;
    }

    public void setFriend(Dog friend) {
        this.friend = friend;
    }

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

    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sheep;
    }
}
Dog friend = new Dog();
friend.setName("Tom");
friend.setAge(1);
Sheep sheep = new Sheep();
sheep.setName("Dolly");
sheep.setAge(2);
sheep.setFriend(friend);

Sheep sheep2 = (Sheep) sheep.clone();

// 属性值相同
System.out.println("sheep:" + sheep);
System.out.println("sheep2:" + sheep2);
// 对象的地址不同
System.out.println("sheep.hashCode:" + sheep.hashCode());
System.out.println("sheep2.hashCode:" + sheep2.hashCode());
// 引用数据类型成员变量的地址相同
System.out.println("sheep.friend:" + sheep.getFriend().hashCode());
System.out.println("sheep2.friend:" + sheep2.getFriend().hashCode());

深拷贝

不论成员变量是基本数据类型还是引用数据类型,深拷贝都会复制一份新的给新对象。

实现方式 1:重写 clone() 实现深拷贝

public class Dog implements Cloneable {
    private String name;
    private int age;

    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
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

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

public class Sheep implements Cloneable {
    private String name;
    private int age;
    private Dog friend;

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

    public Dog getFriend() {
        return friend;
    }

    public void setFriend(Dog friend) {
        this.friend = friend;
    }

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

    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            // 对基本数据类型的拷贝
            sheep = (Sheep) super.clone();
            // 对引用数据类型的拷贝;需要引用类型也实现 Cloneable 接口
            sheep.friend = (Dog) friend.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sheep;
    }
}
Dog friend = new Dog();
friend.setName("Tom");
friend.setAge(1);
Sheep sheep = new Sheep();
sheep.setName("Dolly");
sheep.setAge(2);
sheep.setFriend(friend);

Sheep sheep2 = (Sheep) sheep.clone();

// 属性值相同
System.out.println("sheep:" + sheep);
System.out.println("sheep2:" + sheep2);
// 对象的地址不同
System.out.println("sheep.hashCode:" + sheep.hashCode());
System.out.println("sheep2.hashCode:" + sheep2.hashCode());
// 引用数据类型成员变量的地址也不相同
System.out.println("sheep.friend:" + sheep.getFriend().hashCode());
System.out.println("sheep2.friend:" + sheep2.getFriend().hashCode());

实现方式 2:通过对象序列化实现深拷贝

public class Dog implements Serializable {
    private String name;
    private int age;

    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
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

// 所有相关对象都要实现 Serializable 接口,包括 Dog
public class Sheep implements Serializable {
    private String name;
    private int age;
    private Dog friend;

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

    public Dog getFriend() {
        return friend;
    }

    public void setFriend(Dog friend) {
        this.friend = friend;
    }

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

    // 通过对象的序列化实现深拷贝
    public Object deepClone() {
        Sheep copySheep = null;

        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);
            copySheep = (Sheep) ois.readObject();
        } catch (IOException | SecurityException | NullPointerException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
                if (oos != null) {
                    oos.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (ois != null) {
                    ois.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return copySheep;
    }
}
Dog friend = new Dog();
friend.setName("Tom");
friend.setAge(1);
Sheep sheep = new Sheep();
sheep.setName("Dolly");
sheep.setAge(2);
sheep.setFriend(friend);

Sheep sheep2 = (Sheep) sheep.deepClone();

// 属性值相同
System.out.println("sheep:" + sheep);
System.out.println("sheep2:" + sheep2);
// 对象的地址不同
System.out.println("sheep.hashCode:" + sheep.hashCode());
System.out.println("sheep2.hashCode:" + sheep2.hashCode());
// 引用数据类型成员变量的地址也不相同
System.out.println("sheep.friend:" + sheep.getFriend().hashCode());
System.out.println("sheep2.friend:" + sheep2.getFriend().hashCode());