设计模式-原型模式

5、原型模式
原型模式是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,属于创建型模式。
创建原型接口

package com.jdwa.prototype;

public interface IPrototype<T> {
    T clone();
}

创建具体的需要克隆的对象:

package com.jdwa.prototype;

public class ConcretePrototype implements IPrototype {
    
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "age=" + age +
                ", name=‘" + name + ‘\‘‘ +
                ‘}‘;
    }

    @Override
    public ConcretePrototype clone() {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setAge(this.age);
        concretePrototype.setName(this.name);
        return concretePrototype;
    }
}

测试代码:

package com.jdwa.prototype;

public class Client {
    public static void main(String[] args) {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setName("TOM");
        concretePrototype.setAge(25);

        ConcretePrototype cloneProtoType = concretePrototype.clone();

        System.out.println(concretePrototype);
        System.out.println(cloneProtoType);
        
    }
}

当然了,上面的方法不用我们自己实现,JDK已经帮我们实现好了,只需要实现一下Cloneable接口。

package com.jdwa.prototype;

import lombok.Data;

@Data
public class ConcreteProtoType2 implements Cloneable {
    private int age;
    private String name;

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

    @Override
    public String toString() {
        return "ConcreteProtoType2{" +
                "age=" + age +
                ", name=‘" + name + ‘\‘‘ +
                ‘}‘;
    }
}

但是当原型对象属性包含对象如List时,修改克隆对象同时原型对象也会被修改,这就是我们常说的浅克隆,这显然不符合我们遇到的大部分场景。
浅克隆只是复制了值类型数据,没有复制引用对象。这就需要用到深克隆了。

使用序列化进行深克隆

package com.jdwa.prototype;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import lombok.Data;

import java.io.*;
import java.util.List;

@Data
public class ConcretePrototype3 implements Cloneable, Serializable {
    
    private int age;
    private String name;
    private List<String> hobbis;

    @Override
    protected ConcretePrototype3 clone()  {
        try {
            return (ConcretePrototype3) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public ConcretePrototype3 deepClone(){
        
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            
            return (ConcretePrototype3) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String toString() {
        return "ConcretePrototype3{" +
                "age=" + age +
                ", name=‘" + name + ‘\‘‘ +
                ", hobbis=" + hobbis +
                ‘}‘;
    }
}

测试代码:

package com.jdwa.prototype;

import java.util.ArrayList;
import java.util.List;

public class Client {
    public static void main(String[] args) {
//        testSimpleClone();
        deepClone();
        /*
            原型:ConcretePrototype3{age=25, name=‘TOM‘, hobbis=[游泳, 跑步]}
            克隆:ConcretePrototype3{age=25, name=‘TOM‘, hobbis=[游泳, 跑步, 俯卧撑]}
            false
            原型的爱好:[游泳, 跑步]
            克隆的爱好:[游泳, 跑步, 俯卧撑]
            false
         */

    }

    private static void testSimpleClone(){
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setName("TOM");
        concretePrototype.setAge(25);

        ConcretePrototype cloneProtoType = concretePrototype.clone();

        System.out.println(concretePrototype);
        System.out.println(cloneProtoType);
    }

    private static void deepClone(){
        ConcretePrototype3 concretePrototype3 = new ConcretePrototype3();
        concretePrototype3.setAge(25);
        concretePrototype3.setName("TOM");
        List<String> hobbis = new ArrayList<>(3);
        hobbis.add("游泳");
        hobbis.add("跑步");
        concretePrototype3.setHobbis(hobbis);

        ConcretePrototype3 cloneObj = concretePrototype3.deepClone();
        cloneObj.getHobbis().add("俯卧撑");

        System.out.println("原型:"+concretePrototype3);
        System.out.println("克隆:"+cloneObj);
        System.out.println(concretePrototype3 == cloneObj);

        System.out.println("原型的爱好:"+concretePrototype3.getHobbis());
        System.out.println("克隆的爱好:"+cloneObj.getHobbis());
        System.out.println(concretePrototype3.getHobbis() == cloneObj.getHobbis());

    }
}

当然也可以使用json序列化与反序列化实现

欢迎大家留言,以便于后面的人更快解决问题!另外亦欢迎大家可以关注我的微信公众号,方便利用零碎时间互相交流。共勉!

设计模式-原型模式

设计模式-原型模式

上一篇:elasticsearch 出现 all shards failed 问题解决过程


下一篇:设置请求头中携带cookie,但是不起作用的几种情况总结,针对于客户端解决。