设计模式之原型模式

原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。

在原型模式中的复制分为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种深克隆的方式,使用重写父类的深克隆方式,不适合层级较深的对象,使用序列化的深克隆方式,效率又比较低。因此对于使用哪种克隆方式,要根据具体的情况来定。

 

 

 

 

你可能感兴趣的:(设计模式)