原型模式

java通过实现Cloneable接口, 重写clone方式, 快速实现克隆对象, 每个克隆对象是独立的, 在内存的相应地址也不同.

结构

  • 抽象原型
  • 具体原型
  • 客户类

原型模式

Demo

/**
 * 使用java 自带的 clone 方法
 * 需要实现 Cloneable 接口
 *
 * @author liuzhihang
 * @date 2018/4/3 16:23
 */
@Getter
@Setter
@AllArgsConstructor
public class UserTemplate implements Cloneable {

    private String id;
    private String name;
    /** 构造器 get/set 省略 */
    @Override
    public String toString() {
        return "UserTemplate{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
    @Override
    protected UserTemplate clone() throws CloneNotSupportedException {
        return (UserTemplate) super.clone();
    }
}

测试代码如下:

public class PrototypePatternTest {

    public static void main(String[] args) throws CloneNotSupportedException {

        UserTemplate template = new UserTemplate("123", "默认名称");
        UserTemplate templateClone = template.clone();
        System.out.println(template.toString());
        System.out.println(templateClone.toString());
        System.out.println("template == templateClone: " + (template == templateClone));

        templateClone.setName("修改后的名称");
        System.out.println(template.toString());
        System.out.println(templateClone.toString());
    }
}

输出结果:

UserTemplate{id='123', name='默认名称'}
UserTemplate{id='123', name='默认名称'}
template == templateClone: false
UserTemplate{id='123', name='默认名称'}
UserTemplate{id='123', name='修改后的名称'}

深克隆&浅克隆

浅克隆

在原型类中添加对象属性, ContactInfo, 内容如下:

@Getter
@Setter
@ToString
@AllArgsConstructor
public class ContactInfo {

    private String address;
    private String phone;

}

修改原型类:

@Getter
@Setter
@ToString
@AllArgsConstructor
public class UserTemplate implements Cloneable {

    private String id;

    private String name;

    private ContactInfo contactInfo;

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

测试代码如下:

public class PrototypePatternTest {

    public static void main(String[] args) throws CloneNotSupportedException {

        UserTemplate template = new UserTemplate("123", "默认名称", new ContactInfo("默认", "xxxxxx"));
        UserTemplate templateClone = template.clone();
        System.out.println(template.toString());
        System.out.println(templateClone.toString());
        System.out.println("template == templateClone: " + (template == templateClone));
        System.out.println("地址是否相同: " + (template.getContactInfo() == templateClone.getContactInfo()));
        ContactInfo contactInfo = templateClone.getContactInfo();
        contactInfo.setAddress("修改克隆的地址");
        System.out.println(template.toString());
        System.out.println(templateClone.toString());
    }
}

执行结果:

UserTemplate(id=123, name=默认名称, contactInfo=ContactInfo(address=默认, phone=xxxxxx))
UserTemplate(id=123, name=默认名称, contactInfo=ContactInfo(address=默认, phone=xxxxxx))
template == templateClone: false
地址是否相同: true
UserTemplate(id=123, name=默认名称, contactInfo=ContactInfo(address=修改克隆的地址, phone=xxxxxx))
UserTemplate(id=123, name=默认名称, contactInfo=ContactInfo(address=修改克隆的地址, phone=xxxxxx))

结论: 浅克隆只是克隆当前的原型类, 对原型类中存在对象属性, 拷贝的是对象属性的引用, 指向的还是原型类中同一个对象属性.

深克隆: clone属性

内部对象属性也实现 Cloneable 接口, 并重写 clone() 方法.

@Getter
@Setter
@ToString
@AllArgsConstructor
public class UserTemplate implements Cloneable {

    private String id;
    private String name;
    private ContactInfo contactInfo;

    @Override
    protected UserTemplate clone() throws CloneNotSupportedException {
        UserTemplate clone = (UserTemplate) super.clone();
        clone.contactInfo = (ContactInfo) clone.contactInfo.clone();
        return clone;
    }
}
深克隆: 序列化

也可以使用json序列化 转化再转换回对象.

@Getter
@Setter
@ToString
@AllArgsConstructor
public class UserInfo implements Serializable {
    private String name;
    private Date time;

    public UserInfo deepClone() throws IOException, ClassNotFoundException {

        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);

        oos.writeObject(this);

        ByteArrayInputStream bai = new ByteArrayInputStream(bao.toByteArray());

        ObjectInputStream ois = new ObjectInputStream(bai);
        return (UserInfo) ois.readObject();

    }
}

测试及执行结果:

public class DeepCloneTest {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        UserInfo userInfo = new UserInfo("default", new Date());
        UserInfo userClone = userInfo.deepClone();
        userClone.setTime(new Date(1543890828988L));

        System.out.println(userInfo.deepClone());
        System.out.println(userClone.toString());

    }
}
/**
执行结果如下:
UserInfo(name=default, time=Tue Dec 04 10:34:10 CST 2018)
UserInfo(name=default, time=Tue Dec 04 10:33:48 CST 2018)
*/

   版权声明

文章作者: liuzhihang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源!

 上一篇
建造者模式 建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.
2018-12-03 liuzhihang
下一篇 
抽象工厂模式 抽象工厂模式
工厂的工厂, 在工厂的基础上进行抽象, 用来获取工厂, 然后通过工厂获取一类产品 和工厂方法的主要区别是: 工厂方法每次获取的是单个产品的工厂, 而抽象工厂则是一类产品
2018-11-25