原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
在原型模式中的复制分为2种,一种是浅克隆,一种是深克隆。
我们先来看个浅克隆的例子吧。
//创建订单表并实现克隆接口
public class Order implements Cloneable{
private String orderNo;
private OrderDetail orderDetail;
public OrderDetail getOrderDetail() {
return orderDetail;
}
public void setOrderDetail(OrderDetail orderDetail) {
this.orderDetail = orderDetail;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
@Override
public String toString() {
return "Order{" +
"orderNo='" + orderNo + '\'' +
", orderDetail=" + orderDetail +
'}';
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
//创建订单明细表,并实现克隆接口
public class OrderDetail implements Cloneable{
private String id;
private String name;
private String number;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "OrderDetail{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", number='" + number + '\'' +
'}';
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
//创建测试类,进行测试
public class Test {
public static void main(String[] args) throws CloneNotSupportedException{
Order order1 = new Order();
order1.setOrderNo("aaa");
OrderDetail orderDetail1 = new OrderDetail();
orderDetail1.setId("a1");
orderDetail1.setName("aname");
orderDetail1.setNumber("anum");
order1.setOrderDetail(orderDetail1);
Order order2 = (Order)order1.clone();
order2.setOrderNo("bbb");
OrderDetail orderDetail2 = order2.getOrderDetail();
orderDetail2.setId("b1");
orderDetail2.setName("bname");
orderDetail2.setNumber("bnum");
System.out.println(order1);
System.out.println(order2);
}
}
//输出结果
Order{orderNo='aaa', orderDetail=OrderDetail{id='b1', name='bname', number='bnum'}}
Order{orderNo='bbb', orderDetail=OrderDetail{id='b1', name='bname', number='bnum'}}
从测试结果可以看出,订单aaa和订单bbb的订单号是不一样的,但是订单明细是一样的,因为浅克隆对于基本数据类型克隆的是值,对于非基本类型,克隆的是引用,因此当改变克隆体的引用时,被克隆的属性值也发生了变化,因此改变了bbb订单的订单明细时,aaa订单的明细也被改变了。这显然是不符合我们使用的,为了解决这个问题,引入了深克隆。
那么什么是深克隆呢?
//仅改了订单类的clone方法
public Object clone() throws CloneNotSupportedException{
Order order = (Order) super.clone();
order.setOrderDetail((OrderDetail) order.getOrderDetail().clone());
return order;
//return super.clone();
}
//测试类及方法不变,测试结果如下:
Order{orderNo='aaa', orderDetail=OrderDetail{id='a1', name='aname', number='anum'}}
Order{orderNo='bbb', orderDetail=OrderDetail{id='b1', name='bname', number='bnum'}}
现在可以看到,即使改变了订单bbb中的明细中的值,对订单aaa也没有影响了,因为深克隆把非基本类型的属性值也给复制了。
上面使用的深克隆是通过重写父类的clone()方法,实现的深克隆,但是如果需要克隆的对象引用的层级较深,就会比较繁琐。
因此还可以通过序列化的方式,重写clone()方法。修改后的代码如下。
//order类实现序列化Serializable接口
public class Order implements Cloneable,Serializable{
private String orderNo;
private OrderDetail orderDetail;
public OrderDetail getOrderDetail() {
return orderDetail;
}
public void setOrderDetail(OrderDetail orderDetail) {
this.orderDetail = orderDetail;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
@Override
public String toString() {
return "Order{" +
"orderNo='" + orderNo + '\'' +
", orderDetail=" + orderDetail +
'}';
}
//使用序列化后重写的clone()方法
public Order clone() {
Order order = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try{
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.close();
}catch(IOException e){
e.printStackTrace();
}
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
try{
ObjectInputStream ois = new ObjectInputStream(bis);
order = (Order)ois.readObject();
ois.close();
}catch (IOException | ClassNotFoundException e ){
e.printStackTrace();
}
return order;
}
//orderDetail订单明细类实现序列化Serializable接口
public class OrderDetail implements Cloneable, Serializable {
private String id;
private String name;
private String number;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "OrderDetail{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", number='" + number + '\'' +
'}';
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
//测试类不发生变化,测试结果如下;
Order{orderNo='aaa', orderDetail=OrderDetail{id='a1', name='aname', number='anum'}}
Order{orderNo='bbb', orderDetail=OrderDetail{id='b1', name='bname', number='bnum'}}
从上面测试结果可知,和之前的深克隆的方式,结果是一样的。
2种深克隆的方式,使用重写父类的深克隆方式,不适合层级较深的对象,使用序列化的深克隆方式,效率又比较低。因此对于使用哪种克隆方式,要根据具体的情况来定。