原型模式-克隆生成对象

一, 举个业务场景来讲明 java

如今咱们有个订单系统,里面有个保存订单的业务功能。这个功能有个需求,就是每当订单产品数量超过1000的时候,系统自动拆分订单,拆分后的全部订单中的产品数量依然不能超过1000,若是超过继续拆分。(有同窗这里可能会问,为何限制产品1000?咱们这里为了方便订单跟踪工做分配缘由,人工订单处理小组的处理能力为1000) 程序员

怎么实现呢? 设计模式

二:不使用设计模式来实现需求,直接上代码吧 ide


/**
 * 订单接口
 */
public interface OrderApi {
    public int getOrderProductNum();

    public void setOrderProductNum(int num);

    public String getOrderInfo();
}



/**
 * 我的订单
 */
public class PersonalOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public PersonalOrder() {}

    public PersonalOrder(String customName, int productId,int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

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

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<我的订单>,订购人:"+this.customName+",订购产品:"+this.productId+",订购数量:"+this.orderProductNum;
    }
}



/**
 * 企业订单
 */
public class EnterpriseOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public EnterpriseOrder() {
    }

    public EnterpriseOrder(String customName, int productId,int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

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

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<企业订单>,订购人:"+this.customName+",订购产品:"+this.productId+",订购数量:"+this.orderProductNum;
    }
}


ok,订单接口定义完了, 测试

从我代码中能够看到咱们这里有两种订单类型,我的订单和企业订单, this

下面继续写订单处理类: spa

(考虑到每一个订单有可能产品数量超过1000,就意味着继续拆单,因此咱们要用到循环) 设计


/**
 * 订单处理对象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判断产品数量是否大于1000
        while (order.getOrderProductNum()>1000) {
            //若是大于继续拆分
            //再建立一份订单
            OrderApi newOrder = null;
            //如何建立??
        }
    }
}


这里我先否则代码一步到位,咱们来思考一个问题,拆分后的新订单如何建立??? code

难道咱们要new 个订单吗,那么new 哪一种类型的订单呢? 对象

是new 我的订单,仍是企业订单?你根本没法断定!

小白这里确定傻眼了,

但有经验的程序员,确定会指出一个简单的办法,就是使用instanceof来断定订单类型

且看我代码示例:


/**
 * 订单处理对象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判断产品数量是否大于1000
        while (order.getOrderProductNum()>1000) {
            //若是大于继续拆分
            //再建立一份订单
            OrderApi newOrder = null;
            if (order instanceof PersonalOrder){
                PersonalOrder p = (PersonalOrder) order;
                newOrder = new PersonalOrder(p.getCustomName(),p.getProductId(),1000);
            }else if(order instanceof EnterpriseOrder){
                EnterpriseOrder e = (EnterpriseOrder) order;
                newOrder = new EnterpriseOrder(e.getCustomName(),e.getProductId(),1000);
            }
            System.out.println(newOrder.getOrderInfo());
            order.setOrderProductNum(order.getOrderProductNum()-1000);
            //(后续业务代码省略...)
        }
        System.out.println(order.getOrderInfo());
    }
}


咱们模拟个客户端测试下: 测试下我的订单和企业订单


/**
 * 客户端测试
 */
public class Client {
    public static void main(String[] args) {
        PersonalOrder personalOrder = new PersonalOrder("洋哥",6666,6925);
        OrderBusiness ob = new OrderBusiness();
        ob.saveOrder(personalOrder);
    }
}





/**
 * 客户端测试
 */
public class Client {
    public static void main(String[] args) {
        EnterpriseOrder enterpriseOrder = new EnterpriseOrder("洋哥股份有限公司",518,5199);
        OrderBusiness ob = new OrderBusiness();
        ob.saveOrder(enterpriseOrder);
    }
}




以上订单拆分功能实现基本知足需求!

可是若是我是你的leader的话, 这样的代码在review的时候,确定是没法经过的!

这里的问题就是出来订单处理这个地方,从软件工程学的角度来讲订单处理类是不须要关心甚至不须要知道具体订单类型的!若是按照以上实现方式,那么之后个人订单类型增长了一个大企业订单,那么我是否是要修改订单处理类,有人说了,添加几行代码很不麻烦的,那若是代码不是你写的呢?写这个块代码的人已经离职或转行了呢?何况修改代码自己就不符合设计理念!所以上述实现方式确实不太好。

三,利用原型模式,从新实现的解决方案

原型模式的定义:用原型实例指定建立对象的种类,并经过拷贝这些原型建立新的对象。

 四,使用原型模式,从新实现,代码示例


/**
 * 订单接口
 */
public interface OrderApi {
    public int getOrderProductNum();

    public void setOrderProductNum(int num);

    public String getOrderInfo();

    /**
     * 原型模式增长代码
     * @return 订单原型的克隆实例
     */
    public OrderApi cloneOrder();
}


如何克隆呢?有的同窗可能想到 this  ,在克隆方法中直接返回this,这样是打错特错了

/**
 * 我的订单
 */
public class PersonalOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public PersonalOrder() {}

    public PersonalOrder(String customName, int productId,int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

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

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<我的订单>,订购人:"+this.customName+",订购产品:"+this.productId+",订购数量:"+this.orderProductNum;
    }
    /**
     * 原型模式增长代码
     * @return 订单原型的克隆实例
     */
    public OrderApi cloneOrder(){
        PersonalOrder order = new PersonalOrder(this.getCustomName(),this.productId,this.getOrderProductNum());
        return  order;
    }
}



/**
 * 企业订单
 */
public class EnterpriseOrder implements OrderApi {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public EnterpriseOrder() {
    }

    public EnterpriseOrder(String customName, int productId, int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public int getProductId() {
        return productId;
    }

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

    @Override
    public void setOrderProductNum(int num) {
        this.orderProductNum = num;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<企业订单>,订购单位:" + this.customName + ",订购产品:" + this.productId + ",订购数量:" + this.orderProductNum;
    }

    /**
     * 原型模式增长代码
     *
     * @return 订单原型的克隆实例
     */
    public OrderApi cloneOrder() {
        EnterpriseOrder order = new EnterpriseOrder(this.getCustomName(), this.productId, this.getOrderProductNum());
        return order;
    }
}



/**
 * 订单处理对象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判断产品数量是否大于1000
        while (order.getOrderProductNum()>1000) {
            //若是大于继续拆分
            //再建立一份订单
            OrderApi newOrder = order.cloneOrder();
            newOrder.setOrderProductNum(1000);
            System.out.println(newOrder.getOrderInfo());
            order.setOrderProductNum(order.getOrderProductNum()-1000);
            //(后续业务代码省略...)
        }
        System.out.println(order.getOrderInfo());
    }
}



/**
 * 客户端测试
 */
public class Client {
    public static void main(String[] args) {
        EnterpriseOrder enterpriseOrder = new EnterpriseOrder("洋哥股份有限公司",518518,6699);
        OrderBusiness ob = new OrderBusiness();
        ob.saveOrder(enterpriseOrder);
    }
}



有的同窗说了,java的Object自己就有克隆方法啊,还写这么麻烦?

虽然java有clone方法,但咱们本身实现出来也是颇有意义的,是为了更好,跟完整第理解克隆模式,别急,标题六我会介绍如何使用java自带的clone方法。

五,原型模式两个功能

原型模式实际包含两个功能:

1)经过克隆建立新的对象实例。

2)为克隆出来的新对象实例复制原型实例属性值。


六:java中的克隆,须要克隆功能的类只须要实现java.lang.Cloneable

/**
 * 订单接口
 */
public interface OrderApi {
    public void setOrderProductNum(int orderProductNum);
    public int getOrderProductNum();
    public String getOrderInfo();
    public Object cloneOrder();
}



/**
 * 企业订单
 */
public class EnterpriseOrder implements OrderApi,Cloneable {

    private int orderProductNum = 0;
    private String customName;
    private int productId = 0;

    public EnterpriseOrder() {
    }

    public EnterpriseOrder(String customName, int productId, int orderProductNum) {
        this.customName = customName;
        this.productId = productId;
        this.orderProductNum = orderProductNum;
    }


    @Override
    public void setOrderProductNum(int orderProductNum) {
         this.orderProductNum = orderProductNum;
    }

    @Override
    public int getOrderProductNum() {
        return this.orderProductNum;
    }

    public String getOrderInfo() {
        return "<企业订单>,订购单位:" + this.customName + ",订购产品:" + this.productId + ",订购数量:" + this.orderProductNum;
    }

    public Object cloneOrder(){
        Object object = null;
        try {
            //java内置克隆实现,直接调用父类的方法
            object = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return object;
    }
}



/**
 * 订单处理对象
 */
public class OrderBusiness {

    public void saveOrder(OrderApi order) {
        //判断产品数量是否大于1000
        while (order.getOrderProductNum()>1000) {
            //若是大于继续拆分
            //再建立一份订单
            OrderApi newOrder = (OrderApi) order.cloneOrder();
            newOrder.setOrderProductNum(1000);
            System.out.println(newOrder.getOrderInfo());
            order.setOrderProductNum(order.getOrderProductNum()-1000);
            //(后续业务代码省略...)
        }
        System.out.println(order.getOrderInfo());
    }
}


测试结果和咱们本身实现的结果是如出一辙的!

我想这里我有必要介绍下深度克隆和浅度克隆。

以上的代码示例属于浅度克隆!

咱们本身能够实现深度克隆,就是要把须要克隆的类中的全部引用对象都要克隆!

固然咱们也可使用java自带的克隆实现深度克隆,ok,以下图代码示例:

 七: 何时使用原型模式

1)若是一个系统想要独立于它想要使用的对象时,可使用原型模式。

2)若是须要实例化的类是运行时动态指定时,可使用原型模式。

两者,都是经过克隆获得须要的实例

八:原型模式和抽象工厂的区别

两者功能有些类似,都是动态获取一个新对象实例。

不一样之处在于,原型模式着眼于如何创造出实例,选择的是克隆方式。而抽象工厂着眼点在于如何创造产品簇,至于如何建立产品簇中的产品对象实例,抽象工厂模式并不关心 。正由于关注点不同,两者能够配合使用。

相关文章
相关标签/搜索