第7章 创建型模式—原型模式

1. 原型模式(Prototype pattern)的定义

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

  ①通过克隆来创建新的对象实例

  ②新的对象实例复制原型实例属性的值

(2)原型模式的结构和说明

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

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

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

(3)思考原型模式

  ①原型模型的本质克隆生成对象

  ②原型模式可以用来解决“只知接口而不知实现的问题”,出现一种“接口造接口”的假象。

  ③原型模式的重心还是在创建新的对象实例。至于创建出来的对象,其属性的值是否一定要和原型对象完全一样,这并没有强制规定,但一般会拷贝成一样的。

  ④通过克隆出来实例是原型实例是两个完全独立的实例,他们之间没有关联。

【编程实验】订单拆分处理

//创建型模式:原型模式
//订单处理:
/*
    功能需求:因每个工作小组的处理能力上限是1000,现要求每当订单预定产品数量超过1000时,
把订单拆分为两份来保存,如果还是超过1000,那就继续拆分,直到不超过1000.
*/
#include <iostream>
#include <string>
#include <sstream>

using namespace std;
//*************************辅助类:************************
//定义产品原型的接口,这个产品是为了演示深拷贝
class ProductPrototype
{
public:
    virtual ProductPrototype* clone() = 0;
};

class Product :public ProductPrototype
{
private:
    string productId; //产品编号
    string name;      //产品名称
public:
    string& getName(){return name;}
    void setName(string name){this->name = name;}

    string& getProductId(){return productId;}
    void setProductId(string productId){this->productId = productId;}

    string toString()
    {
        return "ProductId="+productId+", productName="+name;
    }

    //克隆方法
    ProductPrototype* clone()
    {
        //创建一个新的订单,然后把本实例的数据复制过去
        Product* product = new Product();
        product->setProductId(productId);
        product->setName(name);

        return product;
    }
};

//*************************订单原型**************************

//订单的接口,声明了可以克隆自身的方法
class OrderApi
{
public:
    virtual string toString() = 0;
    virtual int getOrderProductNum()=0;
    virtual void setOrderProductNum(int num) = 0;
    virtual OrderApi* clone() = 0;
};

//个人订单对象
class PersonalOrder : public OrderApi
{
private:
    Product* product;
public:
    PersonalOrder():orderProductNum(0){product = NULL;}

    string toString()
    {
        ostringstream oss;
        oss << orderProductNum;
        return ("PersonalOrder‘s Order="+customerName+" "+
                                "productName="+product->getName()+" "+
                                "productId="+product->getProductId()+" "+
                                "OrderNum="+oss.str());
    }

    OrderApi* clone()
    {
       PersonalOrder* order = new PersonalOrder();
       order->setName(customerName);
       order->setProduct((Product*)product->clone());//深度克隆
       order->setOrderProductNum(orderProductNum);
       return order;
    }

    int getOrderProductNum()
    {
        return orderProductNum;
    }

    void setOrderProductNum(int num)
    {
        orderProductNum = num;
    }

    string& getName()
    {
        return customerName;
    }

    void setName(string name)
    {
        customerName = name;
    }

    Product* getProduct(){return product;}
    void setProduct(Product* product)
    {
        this->product = product;
    }

private:
    string customerName;
    string productId;
    int orderProductNum;
};

//企业订单对象
class EnterpriseOrder : public OrderApi
{
private:
    Product* product;
public:
    EnterpriseOrder():orderProductNum(0){product = NULL;}

    string toString()
    {
        ostringstream oss;
        oss << orderProductNum;
        return ("EnterpriseOrder‘s Order="+enterpriseName+" "
                                "productName="+product->getName()+" "+
                                "productId="+product->getProductId()+" "+
                                "OrderNum="+oss.str());
    }

    OrderApi* clone()
    {
       EnterpriseOrder* order = new EnterpriseOrder();
       order->setName(enterpriseName);
       order->setProduct((Product*)product->clone());
       order->setOrderProductNum(orderProductNum);
       return order;
    }

    int getOrderProductNum()
    {
        return orderProductNum;
    }

    void setOrderProductNum(int num)
    {
        orderProductNum = num;
    }

    string& getName()
    {
        return enterpriseName;
    }

    void setName(string name)
    {
        enterpriseName = name;
    }

    Product* getProduct(){return product;}
    void setProduct(Product* product)
    {
        this->product = product;
    }

private:
    string enterpriseName;
    string productId;
    int orderProductNum;
};

//*********************************订单拆分过程********************
//处理订单
class OrderBusiness
{
public:
    //saveOrder传入的是订单接口类型的对象实例,这里只知道
    //订单接口的类型,并不知道其具体类型是个人订单还是企业订单

    void saveOrder(OrderApi& order)
    {
        //1:判断当前的预定产品数量是否大于1000
        while(order.getOrderProductNum()> 1000)
        {
            //2.如果大于,还需要继续拆分

            //2.1 再新建一份订单,跟传入的订单除了数量不一样外,
            //其他都相同
            //如果不采用克隆的方式,下面这行是不知道如何new一个
            //对象的,因为order只是个接口,不能直接实例化。而
            //Clone的作用在运行时order这个具体的对象是知道自己的类型的
            //所以可以通过自身克隆出一个新的对象。
            OrderApi* newOrder = order.clone();

            //然后进行赋值,产品数量为1000
            newOrder->setOrderProductNum(1000);

            //2.2 原来的订单保留,把数量减少1000
            order.setOrderProductNum(order.getOrderProductNum()-1000);

            //然后是业务处理功能,省略了,打印输出看一下
            cout << "split order="+newOrder->toString()<<endl;
        }

        //3.不超过,那就直接业务功能处理,省略了,打印输出看一下
        cout << "order="+order.toString()<<endl;
    }
};

int main()
{
    //客户端调用例子

    //创建订单对象,这里为了演示简单,直接new了
    PersonalOrder* op = new PersonalOrder();
    //EnterpriseOrder* op = new EnterpriseOrder();

    //设置产品
    Product* product = new Product();
    product->setName("Product1");
    product->setProductId("P0001");

    //设置订单数据
    op->setProduct(product);
    op->setOrderProductNum(2925);
    op->setName("SantaClaus");

    //这里获取业务处理的类,也直接new了
    OrderBusiness* ob = new OrderBusiness();

    // //调用业务来保存订单对象
    ob->saveOrder(*op);    

    return 0;
}

(4)原型模式的主要功能:通过克隆来创建新的对象实例。

  ①原型模式从某种意义上说,是new操作。但只是“类似于new”,而不是“就是new”。因为new一个对象实例,一般属性是没有值或只有默认值;而克隆一个实例,通常与原型对象的属性值是一样的。

  ②原型实例和克隆实例本质上是两个不同的实例,它们之间是没有关联的。即一个实例的属性值发生改变,不会影响另一个实例。

2. 浅度克隆和深度克隆

(1)浅度克隆:只负责克隆按值传递的数值

(2)深度克隆:除了浅度克隆要克隆的值外,还负责克隆指针所指对象的数据。

3. 原型模式的优缺点

(1)优点

  ①对客户端隐藏具体的实现类型:客户端只知道原型接口的类型,从而减少了客户端对这些具体实现类型的依赖。

  ②在运行时动态改变具体的实现类型:原型模式可以在运行期间,由客户来注册符合原型接口的实现类型,也可以动态地改变具体的实现类型。表面看起来接口没有任何变化,但其实运行的己经是另一个类实例了。因为克隆一个原型就类似于实例化一个类。

(2)缺点

  ①每个原型的子类都必须实现clone接口

  ②当原型实例中出现复杂对象时,会递归对克隆其他对象。

  ③当原型内部包括一些不支持拷贝的对象时,可以导致克隆失败。

4.原型模式的使用场景

(1)在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据

(2)希望对目标对象的修改不影响既有的原型对象(深度克隆的时候可以完全互不影响)。

(3)创建对象时,只知道接口,可以这克隆原型来得到。

(4)需要实例化的类是在运行时刻动态指定时,可以使用原型模式。

时间: 2024-08-30 00:59:28

第7章 创建型模式—原型模式的相关文章

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

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! 概述 原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据. 原型模式要求对象实现一个可以"克隆"自身的接口,这样就可以通过

&quot;围观&quot;设计模式(10)--创建型之原型模式(Prototype Pattern)

原型模式是创建型模式的一种,其特点在于通过"复制"一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的"原型",这个原型是可定制的. 原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效:或者创建值相等,只是命名不一样的同类数据.----WIKIPEDIA 首先看下面这样的一个例子,使用本人自黑一下,实现Clonable接口然后实现它的clone的方法,然后通过该方法对这个对象进行克隆.看是不是像我们

java语言实现创建型设计模式—原型模式(Prototype)

一.描述 原型模式是通过一个原型对象来标明要创建的对象的类型,然后用复制这个原型对象的方法来拷贝创建更多的同类型对象.例如我们在程序的动态运行过程中有了一个对象,这个对象中包含了一系列的有效数据,我们此时需要一个和该对象完全相同的新对象,并且在拷贝之后,新旧对象之间没有任何联系,对任何一个对象的更改都不影响另一个对象. 在java中所有类都默认继承自java.lang.Object类,在这个Object类中有一个clone()方法,该方法将返回Object对象的一个拷贝. 我们让需要被拷贝的类实

【创建型】原型模式

原型模式主要是用原型实例指定创建原型对象的种类,并且通过拷贝原型创建新对象.最简单的理解就是克隆.就如cocos2d-x中的 class Clonable::clone();该模式的主要目的是可以在运行时,随时创建出某个对象的副本,并且副本具有与本体一样的状态信息.类图参考如下: 模式的编码结构参考如下: 1 namespace propotype 2 { 3 /*******************************************************************

05 【创建型】原型模式 理解克隆对象~

原型模式(克隆对象) 用于创建重复的对象,用克隆对象的方式代替new 关键字的使用. 就好比细胞分裂,最开始的一个细胞通过自我复制,分裂成两个.两个分裂成四个,依次指数增长 这里就涉及到一个概念,就是创建重复的对象,就好比细胞分裂的时候就是在重复创建对象,我们可以让对象实现Cloneable接口 通过父类的clone() 方法进行创建相同的对象,这里的相同是指有相同的属性,但是他们在内存中却有不同的引用存在 代码理解 对象实现Cloneable 重写父类的clone方法 public class

创建型-工厂方法模式

1.工厂方法模式意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使一个类的实例化延迟到其子类. 2.应用场景: 考虑一个榨汁机的应用场景.榨汁机可以用来制作苹果汁.西瓜汁.橘汁等,即榨汁机可以用来制作水果汁.但是,夏天的冷饮店中,为了提高制作水果汁的效率和防止味道互串等情况,可能需要分别准备三个水果榨汁机,分别用来生产苹果汁.西瓜汁.橘汁等. 3.工厂方法模式类图: 角色: Product:定义工厂方法所创建对象.如场景描述中的果汁. ConcreteP

创建型-抽象工厂模式学习

1.抽象工厂模式的意图: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 2.抽象工厂模式的适用性: 一个系统要独立于它的产品的创建.组合和表示时. 一个系统要由多个产品系列中的一个来配置时. 当你要强调一系列相关的产品对象的设计以便进行联合使用时. 当你提供一个产品类库,而只想显示它们的接口而不是实现时. 3.场景描述: 考虑一个生产多种不同风格的家具的工厂(FurnitureFactory),不同风格的家具系列可以提供不同的门.窗.地板等的组合,为同一所住房可以提供不同

(五)(创建型模式)原型模式

一.原型模式(prototype pattern): 使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.原型模式是一种对象创建型模式. 二.应用场景: 对象的创建非常复杂,可以使用原型模式快捷的创建对象.在运行过程中不知道对象的具体类型,可使用原型模式创建一个相同类型的对象,或者在运行过程中动态的获取到一个对象的状态. 三.应用实例: 动物界的掌控者Tom,想要再建造一辆奥迪车,但是再去生产比较麻烦,有没有别的方法快速获取呢? 四.方案: UML图: 代码1: package c

第5章 创建型模式—抽象工厂模式

1. 抽象工厂的定义 (1)提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类 ①只需各要知道创建一系列对象的接口,而无需知道具体使用的是哪一个实现 ②这一系列对象是相关或相互依赖的,也就是说既要创建对象,还要约束它们之间的关系. ③一系列对象是构建新对象所需要的组成部分,并且对象之间相互有约赖.如电脑由CPU和主板等组成,但CPU的针脚数和主板提供的插口必须是匹配的,否则无法组装. (2)产品族和产品等级 ①产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等