原型模式

发布 : 2018-12-03 分类 : 设计模式 浏览 :

介绍

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
原文链接 : https://liuzhihang.com/2018/12/03/prototype-mode.html
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

博客已萌萌哒运行(●'◡'●)ノ♥
Theme - BMW | Made With 💗 | Powered by GodBMW