`

原型模式2

 
阅读更多

9.2  解决方案

9.2.1  原型模式来解决

用来解决上述问题的一个合理的解决方案就是原型模式。那么什么是原型模式呢?

(1)原型模式定义

 

(2)应用原型模式来解决的思路

仔细分析上面的问题,在saveOrder方法里面,已经有了订单接口类型的对象实例,是从外部传入的,但是这里只是知道这个实例对象的种类是订单的接口类型,并不知道其具体的实现类型,也就是不知道它到底是个人订单还是企业订单,但是现在需要在这个方法里面创建一个这样的订单对象,看起来就像是要通过接口来创建对象一样。

原型模式就可以解决这样的问题,原型模式会要求对象实现一个可以“克隆”自身的接口,这样就可以通过拷贝或者是克隆一个实例对象本身,来创建一个新的实例。如果把这个方法定义在接口上,看起来就像是通过接口来创建了新的接口对象。

这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,也不关心它的具体实现,只要它实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。

9.2.1  模式结构和说明

原型模式的结构如图9.1所示:

 

图9.1  原型模式结构示意图

Prototype

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

ConcretePrototype

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

Client

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

9.2.3  原型模式示例代码

(1)先来看看原型接口的定义,示例代码如下:

/**

 * 声明一个克隆自身的接口

 */

public interface Prototype {

    /**

     * 克隆自身的方法

     * @return 一个从自身克隆出来的对象

     */

    public Prototype clone();

}

(2)接下来看看具体的原型实现对象,示例代码如下:

/**

 * 克隆的具体实现对象

 */

public class ConcretePrototype1 implements Prototype {

    public Prototype clone() {

       //最简单的克隆,新建一个自身对象,由于没有属性,就不去复制值了

       Prototype prototype = new ConcretePrototype1();

       return prototype;

    }

}

/**

 * 克隆的具体实现对象

 */

public class ConcretePrototype2 implements Prototype {

    public Prototype clone() {

       //最简单的克隆,新建一个自身对象,由于没有属性,就不去复制值了

       Prototype prototype = new ConcretePrototype2();

       return prototype;

    }

}

       为了跟上面原型模式的结构示意图保持一致,因此这两个具体的原型实现对象,都没有定义属性。事实上,在实际使用原型模式的应用中,原型对象多是有属性的,克隆原型的时候也是需要克隆原型对象的属性的,特此说明一下。

(3)再看看使用原型的客户端,示例代码如下:

/**

 * 使用原型的客户端

 */

public class Client {

    /**

     * 持有需要使用的原型接口对象

     */

    private Prototype prototype;

    /**

     * 构造方法,传入需要使用的原型接口对象

     * @param prototype 需要使用的原型接口对象

     */

    public Client(Prototype prototype){

       this.prototype = prototype;

    }

    /**

     * 示意方法,执行某个功能操作

     */

    public void operation(){

       //会需要创建原型接口的对象

       Prototype newPrototype = prototype.clone();

    }

}

9.2.4  使用原型模式重写示例

       要使用原型模式来重写示例,先要在订单的接口上定义出克隆的接口,然后要求各个具体的订单对象克隆自身,这样就可以解决:在订单处理对象里面通过订单接口来创建新的订单对象的问题。

       使用原型模式来重写示例的结构如图9.2所示:

 

图9.2  使用原型模式来重写示例的结构示意图

下面一起来看看具体的实现。

(1)复制谁和谁来复制的问题

有了一个对象实例,要快速的创建跟它一样的实例,最简单的办法就是复制?这里又有两个小的问题

  • 复制谁呢?当然是复制这个对象实例,复制实例的意思是连带着数据一起复制。
  • 谁来复制呢?应该让这个类的实例自己来复制,自己复制自己。

       可是每个对象不会那么听话,自己去实现复制自己的。于是原型模式决定对这些对象实行强制要求,给这些对象定义一个接口,在接口里面定义一个方法,这个方法用来要求每个对象实现自己复制自己。

由于现在存在订单的接口,因此就把这个要求克隆自身的方法定义在订单的接口里面,示例代码如下:

/**

 * 订单的接口,声明了可以克隆自身的方法

 */

public interface OrderApi {

    public int getOrderProductNum();

    public void setOrderProductNum(int num);

    /**

     * 克隆方法

     * @return 订单原型的实例

     */

    public OrderApi cloneOrder();

}

(2)如何克隆

定义好了克隆的接口,那么在订单的实现类里面,就得让它实现这个接口,并具体的实现这个克隆方法,新的问题出来了,如何实现克隆呢?

       很简单,只要先new一个自己对象的实例,然后把自己实例中的数据取出来,设置到新的对象实例中去,不就可以完成实例的复制了嘛,复制的结果就是有了一个跟自身一模一样的实例。

       有的朋友可能会说:不用那么费劲吧,直接返回本实例不就可以了?如下:

public Object clone(){

    return this;

}

请注意了,这是一种典型的错误,这么做,每次克隆,客户端获取的其实都是同一个实例,都是指向同一个内存空间的,对克隆出来的对象实例的修改会影响到原型对象实例。

       那么应该怎么克隆呢,最基本的做法就是新建一个类实例,然后把所有属性的值复制到新的实例中,先看看个人订单对象的实现,示例代码如下:

/**

 * 个人订单对象

 */

public class PersonalOrder implements OrderApi{

    private String customerName;

    private String productId;

    private int orderProductNum = 0;

   

    public int getOrderProductNum() {

       return this.orderProductNum;

    }  

    public void setOrderProductNum(int num) {

       this.orderProductNum = num;

    }  

    public String getCustomerName() {

       return customerName;

    }

    public void setCustomerName(String customerName) {

       this.customerName = customerName;

    }

    public String getProductId() {

       return productId;

    }

    public void setProductId(String productId) {

       this.productId = productId;

    }

    public String toString(){

       return "本个人订单的订购人是="+this.customerName

+",订购产品是="+this.productId+",订购数量为="

+this.orderProductNum;

    }  

    public OrderApi cloneOrder() {

       //创建一个新的订单,然后把本实例的数据复制过去

       PersonalOrder order = new PersonalOrder();

       order.setCustomerName(this.customerName);

       order.setProductId(this.productId);

       order.setOrderProductNum(this.orderProductNum);

      

       return order;

    }

}

       接下来看看企业订单的具体实现,示例代码如下:

/**

 * 企业订单对象

 */

public class EnterpriseOrder implements OrderApi{

    private String enterpriseName;

    private String productId;  

    private int orderProductNum = 0;

    public int getOrderProductNum() {

       return this.orderProductNum;

    }  

    public void setOrderProductNum(int num) {

       this.orderProductNum = num;

    }  

    public String getEnterpriseName() {

       return enterpriseName;

    }

    public void setEnterpriseName(String enterpriseName) {

       this.enterpriseName = enterpriseName;

    }

    public String getProductId() {

       return productId;

    }

    public void setProductId(String productId) {

       this.productId = productId;

    }

    public String toString(){

       return "本企业订单的订购企业是="+this.enterpriseName

+",订购产品是="+this.productId+",订购数量为="

+this.orderProductNum;

    }

    public OrderApi cloneOrder() {

       //创建一个新的订单,然后把本实例的数据复制过去

       EnterpriseOrder order = new EnterpriseOrder();

       order.setEnterpriseName(this.enterpriseName);

       order.setProductId(this.productId);

       order.setOrderProductNum(this.orderProductNum);

       return order;

    }  

}

(3)使用克隆方法

这里使用订单接口的克隆方法的,是订单的处理对象,也就是说,订单的处理对象就相当于原型模式结构中的Client。

当然,客户端在调用clone方法之前,还需要先获得相应的实例对象,有了实例对象,才能调用该实例对象的clone方法。

这里使用克隆方法的时候,跟标准的原型实现有一些不同,在标准的原型实现的示例代码里面,客户端是持有需要克隆的对象,而这里变化成了通过方法传入需要使用克隆的对象,这点大家注意一下。示例代码如下:

public class OrderBusiness {

    /**

     * 创建订单的方法

     * @param order 订单的接口对象

     */

    public void saveOrder(OrderApi order){

       //1:判断当前的预定产品数量是否大于1000

       while(order.getOrderProductNum() > 1000){

           //2:如果大于,还需要继续拆分

           //2.1再新建一份订单,跟传入的订单除了数量不一样外,其它都相同

           OrderApi newOrder = order.cloneOrder();

           //然后进行赋值,产品数量为1000

           newOrder.setOrderProductNum(1000);

          

           //2.2原来的订单保留,把数量设置成减少1000

           order.setOrderProductNum(

order.getOrderProductNum()-1000);

          

           //然后是业务功能处理,省略了,打印输出,看一下

           System.out.println("拆分生成订单=="+newOrder);

       }     

       //3:不超过,那就直接业务功能处理,省略了,打印输出,看一下

       System.out.println("订单=="+order);

    }

}

(4)客户端的测试代码,跟前面的示例是完全一样的,这里就不去赘述了,去运行一下,看看运行的效果,享受一下克隆的乐趣。

在上面的例子中,在订单处理对象的保存订单方法里面的这句话“OrderApi newOrder = order.cloneOrder();”,就用一个订单的原型实例来指定了对象的种类,然后通过克隆这个原型实例来创建出了一个新的对象实例。

9.2.5  小提示

看到这里,可能有些朋友会认为:Java的Object里面本身就有clone方法,还用搞得这么麻烦吗?

 

虽然Java里面有clone方法,上面这么做还是很有意义的,可以让我们更好的、更完整的体会原型这个设计模式。当然,后面会讲述如何使用Java里面的clone方法来实现克隆,不要着急。

分享到:
评论

相关推荐

    设计模式之原型模式

    原型模式是设计模式中的一种,它是Java 23种经典设计模式之一,主要用来提高对象创建的效率。在原型模式中,我们通过复制或克隆一个已经存在的对象来创建新的对象,而不是通过构造函数来创建。这种方法尤其适用于当...

    设计模式的原型模式的例子

    原型模式(Prototype Pattern)是软件设计模式中的一种结构型模式,它的主要目的是通过复制已有对象来创建新对象,从而减少创建新对象的成本。在原型模式中,类的实例化过程被替换为对已有实例的克隆操作,尤其适用...

    iOS设计模式之原型模式

    本文将深入探讨一种常见的设计模式——原型模式(Prototype Pattern),并结合具体的iOS应用场景进行解析。 原型模式是一种创建型设计模式,它的主要思想是通过复制已有对象来创建新对象,而不是通过构造函数来创建...

    android设计模式之原型模式

    本文将深入探讨Android设计模式中的“原型模式”(Prototype Pattern),并结合提供的"prototype"压缩包中的示例代码进行解析。 原型模式是一种创建型设计模式,它的主要思想是通过复制已有对象来创建新对象,而...

    设计模式之原型模式Java实现和类设计图

    原型模式(Prototype Pattern)是其中一种行为设计模式,主要用于对象创建。它通过复制已有对象来创建新对象,而不是通过传统的构造函数来创建。在Java中,原型模式可以有效地提高性能,特别是在创建复杂对象时。 #...

    设计模式——原型模式

    原型模式(Prototype Pattern)是一种创建型设计模式,它允许我们通过复制现有的对象来创建新对象,而无需知道具体创建过程的细节。这种模式的核心在于,它提供了一种对象克隆的简便方法,使得对象的创建过程对用户...

    设计模式专题之(五)原型模式---设计模式原型模式示例代码(python--c++)

    原型模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在原型模式中,一个对象可以被克隆以创建新对象,而无需知道具体的创建细节。这种模式在需要重复创建相似对象时非常有用,避免了每次创建新对象时都...

    23种设计模式详解PDF

    设计模式 的分类 总体来说设计模式分为三大类: 创建型模式(5): 工厂方法模式 、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式(7): 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、...

    原型设计模式prototype

    **原型设计模式(Prototype Pattern)**是一种创建型设计模式,它允许我们通过复制现有的对象来创建新对象,而不是通过构造函数来实例化新对象。在面向对象编程中,当我们需要频繁地创建具有相同或相似属性的对象时,...

    设计模式C++学习之原型模式(Prototype)

    本篇文章将深入探讨“原型模式(Prototype)”这一经典的设计模式,它是面向对象设计的一个重要概念,尤其在C++编程中有着广泛的应用。 原型模式是一种创建型设计模式,它的核心思想是通过复制已有对象来创建新对象,...

    设计模式 创建型模式 Prototype模式(原型)

    即原型模式,提供一个已经存在的对象进行新对象创建的接口,一般情况下都是使用Clone接口。 此模式非常简单,简单的说就是复制多个当前对象供使用。Prototype模式允许一个对象再创建另外一个可定制的对象,根本...

    设计模式:可复用面向对象软件的基础--详细书签版

    1.1 什么是设计模式 2 1.2 smalltalk mvc中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 ...

    C#23种设计模式样例代码和UML图

    C#23种设计模式样例代码和UML图等 创建型模式(抽象工厂模式、工厂方法模式、单例模式、建造者模式、原型模式); 行为型模式(策略模式、 迭代器模式、原型模式、职责链模式、 模板方法、 命令模式、 解释器模式、 ...

    设计模式(.PDF)

    1.1 什么是设计模式 2 1.2 Smalltalk MVC中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象...

    《设计模式》中文版(23个设计模式的介绍与运用)

    1.1 什么是设计模式 2 1.2 Smalltalk MVC中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象...

    新版设计模式手册 - C#设计模式(第二版)

    《新版设计模式手册 - C#设计模式(第二版)》是一部深入探讨C#编程中设计模式的权威指南,尤其适合已经有一定C#基础并希望提升软件设计能力的开发者阅读。设计模式是解决软件开发中常见问题的经验总结,是软件工程的...

    设计模式之原型模式.docx

    【设计模式之原型模式】 设计模式是软件工程中的一种最佳实践,是对在特定上下文中反复出现的软件设计问题的解决方案。原型模式属于对象创建型模式,它的主要思想是通过复制已有对象来创建新对象,降低了类的实例化...

Global site tag (gtag.js) - Google Analytics