[设计模式]原型模式

1. 定义

  用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

2. 类图

  

  Prototype:声明一个克隆自身的接口,用来约束想要克隆自己的类,要求它们都要实现这里定义的克隆方法。

  ConcretePrototype:实现Prototype接口的类,这些类真正实现了克隆本身的功能。

  Client:使用原型的客户端,首先要获取到原型实例对象,然后通过原型实例对象克隆本身来创建新的实例对象。

3. 实例

  

package com.jerry.designpattern;
/**
 * 
 * @author Jerry
 * @date 2015年1月20日 上午9:41:10
 */
public interface OrderApi {
    
    /**
     * 获得产品数量
     * @return
     */
    int getProductNumber();
    
    /**
     * 设置产品数量
     * @param num
     */
    void setProductNumber(int num);
    
    /**
     * 克隆订单
     * @return
     */
    OrderApi cloneOrder();
    
}

package com.jerry.designpattern;
/**
 * 
 * @author Jerry
 * @date 2015年1月20日 上午10:01:09
 */
public class OrderBusiness {
    /**
     * 保存订单
     * 如果存在订单的产品数量大于1000,则生成新的订单,直至小于数量1000
     * @param order
     */
    public void saveOrder(OrderApi order) {
        while (order.getProductNumber() > 1000) {
            System.out.println("订单数量为" + order.getProductNumber() + ",超过1000,需要拆分订单。");
            OrderApi newOrder = order.cloneOrder();
            newOrder.setProductNumber(1000);
            order.setProductNumber(order.getProductNumber() - 1000);
            System.out.println("拆分出新的订单:" + newOrder);
        }
        System.out.println("订单:" + order);
    }
}

package com.jerry.designpattern;
/**
 * 
 * @author Jerry
 * @date 2015年1月20日 上午9:53:50
 */
public class PersonalOrder implements OrderApi{
    
    private String customerName;
    private int productId;
    private int productNumber;
    
    
    
    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    @Override
    public int getProductNumber() {
        // TODO Auto-generated method stub
        return this.productNumber;
    }

    @Override
    public void setProductNumber(int productNumber) {
        // TODO Auto-generated method stub
        this.productNumber = productNumber;
    }

    @Override
    public OrderApi cloneOrder() {
        // TODO Auto-generated method stub
        PersonalOrder order = new PersonalOrder();
        order.setCustomerName(this.customerName);
        order.setProductId(this.productId);
        order.setProductNumber(this.productNumber);
        return order;
    }
    
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "个人订单人为:" + this.customerName + ",订购产品为:" 
                + this.productId + ",订购产品数量为:" + this.productNumber;
    }
    
}

package com.jerry.designpattern;
/**
 * 
 * @author Jerry
 * @date 2015年1月20日 上午9:57:16
 */
public class EnterpriseOrder implements OrderApi{

    private String enterpriseName;
    private int productId;
    private int productNumber;
    
    public String getEnterpriseName() {
        return enterpriseName;
    }

    public void setEnterpriseName(String enterpriseName) {
        this.enterpriseName = enterpriseName;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    @Override
    public int getProductNumber() {
        // TODO Auto-generated method stub
        return this.productNumber;
    }

    @Override
    public void setProductNumber(int productNumber) {
        // TODO Auto-generated method stub
        this.productNumber = productNumber;
    }

    @Override
    public OrderApi cloneOrder() {
        // TODO Auto-generated method stub
        EnterpriseOrder order = new EnterpriseOrder();
        order.setEnterpriseName(this.enterpriseName);
        order.setProductId(this.productId);
        order.setProductNumber(this.productNumber);
        return order;
    }

}

package com.jerry.designpattern;
/**
 * 
 * @author Jerry
 * @date 2015年1月20日 上午10:07:24
 */
public class Client {
    public static void main(String[] args) {
        PersonalOrder order = new PersonalOrder();
        order.setCustomerName("Jerry");
        order.setProductId(123456);
        order.setProductNumber(42223);
        
        OrderBusiness orderBusiness = new OrderBusiness();
        orderBusiness.saveOrder(order);
    }
}

4. 原型模式的功能

  原型模式的功能实际上包含两个方面,第一个是通过克隆来创建新的对象实例,第二个是为克隆出来的对象实例复制原型对象实例属性值。

  原型模式从某种意义上来说,就像是new操作,只是类似于new操作,new一个对象实例,一般属性是没有值或者是默认值,而克隆得到的对象实例,通常都是有值的,一般都是原型对象实例克隆时的值。

5. 深度克隆和浅度克隆

  原型模式是通过克隆创建新的对象实例,因此涉及到深度克隆和浅度克隆的问题,那什么是深度克隆和浅度克隆呢?

  浅度克隆:只负责克隆按值传递的数据,比如基本数据类型、String类型。

  深度克隆:除了浅度克隆要克隆的值外,还负责克隆引用类型的数据,基本上就是被克隆实例所有的属性数据都会被克隆出来。

  实现深度克隆也不是很复杂,只需要实现所有的引用类型的克隆功能,创建时调用它的克隆方法就可以了。

6. 原型的优缺点

  原型的优点有:

    a) 对客户端隐藏具体的实现类型

    b) 在运行时动态改变具体的实现类型

  原型最大的缺点是所有类都要实现克隆方法,特别存在引用类型,比较麻烦。

原文地址:https://www.cnblogs.com/jerry19890622/p/4296165.html