JAVA设计模式笔记(原型模式)

原型模式问题引出:
现在有一个羊对象,现在需要设计程序将这只羊克隆,即创建相同的对象。常见的思路是重复执行new操作,缺点也是显而易见的,每次创建新的对象时,都要获取原对象的属性传入到构造器中,效率较低,使用原型模式可以解决这个问题。

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

原型模式的角色及职责:
1)Prototype:原型类,声明一个克隆自己的接口
2)ConcretePrototype:具体的原型类,实现一个克隆自己的操作
3)Client:让一个原型对象克隆自己,从而创建一个新的对象

克隆羊例子

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

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    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 String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public Sheep getFriend() {
        return friend;
    }

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

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

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

客户端调用:

public class Client {
    public static void main(String[] args) {
        Sheep sheep=new Sheep("tom",1,"白色");
        sheep.setFriend(new Sheep("Jack",2,"黑色"));
        Sheep sheep1= (Sheep) sheep.clone();
        Sheep sheep2= (Sheep) sheep.clone();
        System.out.println("sheep:"+sheep+" hashcode="+sheep.getFriend().hashCode());
        System.out.println("sheep1:"+sheep1+" hashcode="+sheep1.getFriend().hashCode());
        System.out.println("sheep2:"+sheep2+" hashcode="+sheep2.getFriend().hashCode());
    }
}

在这里插入图片描述
可见3个对象引用变量的hashcode都一样,因此是浅拷贝:
浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对直接引用进行拷贝,没有对直接引用指向的对象进行拷贝。这种情况下一个对象改变成员变量会影响到另一个对象的成员变量。
深拷贝是指为所有引用数据类型的成员变量都申请存储空间,并复制每个引用数据类型成员变量所引用的对象,也就是说对象进行深拷贝要对所有对象进行拷贝。

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

例子
原型类

public class DeepPrototype implements Serializable,Cloneable {
    public String name;
    public DeepCloneableTarget deepCloneableTarget;

   //重写clone实现深拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep=null;
        //这里完成基本数据类型和String的克隆
        deep=super.clone();
        //对引用类型的属性进行单独处理
        DeepPrototype deepPrototype= (DeepPrototype) deep;
        deepPrototype.deepCloneableTarget= (DeepCloneableTarget) deepCloneableTarget.clone();
        return deepPrototype;
    }
    //使用对象的序列化实现深拷贝
    public Object deepClone() throws IOException {
        ByteArrayOutputStream byteArrayOutputStream=null;
        ObjectOutputStream objectOutputStream = null ;
        ByteArrayInputStream byteArrayInputStream=null;
        ObjectInputStream objectInputStream=null;
        try {
            //序列化
            byteArrayOutputStream=new ByteArrayOutputStream();
            objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);
            //反序列化
            byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream=new ObjectInputStream(byteArrayInputStream);
            DeepPrototype deepPrototype= (DeepPrototype) objectInputStream.readObject();
            return deepPrototype;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }finally {
            byteArrayOutputStream.close();
            byteArrayInputStream.close();
            objectInputStream.close();
            objectOutputStream.close();
        }
    }
}

原型类中引用类型成员变量的类

public class DeepCloneableTarget implements Serializable,Cloneable {
    private static final long serialVersionUID=1L;
    private String cloneName;
    private String cloneClass;

    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

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

客户端调用

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException, IOException {
        DeepPrototype p=new DeepPrototype();
        p.name="小羊";
        p.deepCloneableTarget=new DeepCloneableTarget("小羊","小羊的类");
        DeepPrototype p1= (DeepPrototype) p.clone();
        DeepPrototype p2= (DeepPrototype) p.deepClone();
        System.out.println("p.name="+p.name+" p.deepCloneableTarget="+p.deepCloneableTarget.hashCode());
        System.out.println("p1.name="+p1.name+" p1.deepCloneableTarget="+p1.deepCloneableTarget.hashCode());
        System.out.println("p2.name="+p1.name+" p2.deepCloneableTarget="+p2.deepCloneableTarget.hashCode());
    }
}

结果
在这里插入图片描述
各对象的引用变量的hashcode不一样,可见实现了深拷贝

发布了56 篇原创文章 · 获赞 3 · 访问量 1616

猜你喜欢

转载自blog.csdn.net/qq_20786911/article/details/103747602