原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,让创建的新对象保持和原有对象相同的内容
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要指定任何创建的细节,就像克隆。
比如如下代码实例:
公共代码Address类:
package cn.pers.sample.prototype;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/20 17:49
*/
@Setter
@Getter
public class Address implements Cloneable, Serializable {
private String prov;
private String city;
private String district;
@Override
public String toString() {
return "Address{" +
"prov='" + prov + '\'' +
", city='" + city + '\'' +
", district='" + district + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
实例1:
创建user对象,内部包含 基本类型 和 引用类型,直接使用原生的clone()方法,注意需要实现 Cloneable,分别打印查看结果比较。
package cn.pers.sample.prototype;
import lombok.Getter;
import lombok.Setter;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* 这里注意实现Cloneable接口很重要,如果没有实现,在进行clone方法调用时会抛出CloneNotSupportedException
*
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/20 17:32
*/
@Getter
@Setter
public class User implements Cloneable, Serializable {
private int id;
private String name;
private Integer age;
private String detail;
private Address address;
private Map<String, String> map;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", detail='" + detail + '\'' +
", address=" + address.toString() +
", map=" + map.keySet().toString() +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
/** 初始化一个对象 */
User user = new User();
user.setId(1);
user.setName("Mars");
user.setAge(12);
user.setDetail("我爱学java,骗人的。");
Address address = new Address();
address.setProv("SH");
address.setCity("SH");
address.setDistrict("SH");
user.setAddress(address);
Map map = new HashMap();
map.put("aaa", "asdas");
map.put("bbb", "anjksna");
user.setMap(map);
System.out.println(user.toString());
System.out.println("原生对象打印结束");
/** 第一轮操作 直接调用clone方法,比较复制后的对象和原有对象 结果 */
User user1 = (User) user.clone();
System.out.println(user1.toString());
System.out.println(user == user1);
System.out.println(user.equals(user1));
System.out.println(user.getDetail() == user1.getDetail());
System.out.println(user.getDetail().equals(user1.getDetail()));
System.out.println(user.getAge() == user1.getAge());
System.out.println(user.getAge().equals(user1.getAge()));
System.out.println(user.getAddress() == user1.getAddress());
System.out.println(user.getAddress().equals(user1.getAddress()));
System.out.println(user.getMap() == user1.getMap());
System.out.println(user.getMap().equals(user1.getMap()));
System.out.println("第一轮结束。。。。。。。。");
/** 第二轮操作 修改后,比较复制后的对象和原有对象 结果 */
user.setDetail("我变了");
System.out.println(user.getDetail());
System.out.println(user1.getDetail());
user.getAddress().setProv("LLLL");
System.out.println(user1.getAddress().toString());
Address address1 = new Address();
address1.setProv("BJ");
address1.setCity("BJ");
address1.setDistrict("BJ");
user.setAddress(address1);
System.out.println(user1.getAddress().toString());
}
}
实例2:
创建user对象,内部包含 基本类型 和 引用类型,修改clone()方法,使用深克隆,注意需要实现序列化,分别打印查看结果比较。
package cn.pers.sample.prototype;
import lombok.Getter;
import lombok.Setter;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* 这里注意实现Cloneable接口很重要,如果没有实现,在进行clone方法调用时会抛出CloneNotSupportedException
*
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/20 17:32
*/
@Getter
@Setter
public class User implements Cloneable, Serializable {
private int id;
private String name;
private Integer age;
private String detail;
private Address address;
private Map<String, String> map;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", detail='" + detail + '\'' +
", address=" + address.toString() +
", map=" + map.keySet().toString() +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
//return super.clone();
//将对象写入流中
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws CloneNotSupportedException {
/** 初始化一个对象 */
User user = new User();
user.setId(1);
user.setName("Mars");
user.setAge(12);
user.setDetail("我爱学java,骗人的。");
Address address = new Address();
address.setProv("SH");
address.setCity("SH");
address.setDistrict("SH");
user.setAddress(address);
Map map = new HashMap();
map.put("aaa", "asdas");
map.put("bbb", "anjksna");
user.setMap(map);
System.out.println(user.toString());
System.out.println("原生对象打印结束");
/** 第一轮操作 直接调用clone方法,比较复制后的对象和原有对象 结果 */
User user1 = (User) user.clone();
System.out.println(user1.toString());
System.out.println(user == user1);
System.out.println(user.equals(user1));
System.out.println(user.getDetail() == user1.getDetail());
System.out.println(user.getDetail().equals(user1.getDetail()));
System.out.println(user.getAge() == user1.getAge());
System.out.println(user.getAge().equals(user1.getAge()));
System.out.println(user.getAddress() == user1.getAddress());
System.out.println(user.getAddress().equals(user1.getAddress()));
System.out.println(user.getMap() == user1.getMap());
System.out.println(user.getMap().equals(user1.getMap()));
System.out.println("第一轮结束。。。。。。。。");
/** 第二轮操作 修改后,比较复制后的对象和原有对象 结果 */
user.setDetail("我变了");
System.out.println(user.getDetail());
System.out.println(user1.getDetail());
user.getAddress().setProv("LLLL");
System.out.println(user1.getAddress().toString());
Address address1 = new Address();
address1.setProv("BJ");
address1.setCity("BJ");
address1.setDistrict("BJ");
user.setAddress(address1);
System.out.println(user1.getAddress().toString());
}
}
输出打印结果:
编者按:综上,原型模式的使用中主要要注意深浅拷贝问题,避免对象修改后相互影响。