场景分析:

前面我们提到,交易对象Trade,还有继承他的债券交易BondTrade、期货交易FutureTrade。

现在有一个需求,需要提供方法将交易拆分成多笔小交易。

代码如下(如果没有clone方法):

/// <summary>
/// 拆分交易
/// </summary>
/// <param name="aTrade">原始交易</param>
/// <param name="aSplitCount">拆分的笔数</param>
public static List<Trade> SplitTrade(Trade aTrade, int aSplitCount)
{
List<Trade> tmpTrades = new List<Trade>(); if (aTrade == null)
{
return null;
} if (aSplitCount == 0)
{
tmpTrades.Add(aTrade);
return tmpTrades;
} for (int i = 0; i < aSplitCount; i++)
{
//注意:此时不能直接赋值,不然新创建的Trade对象跟原始Trade对象指向同一个实例
//Trade trade = aTrade; if (aTrade is BondTrade)
{
//如果交易是债券交易,创建新的债券对象实例
BondTrade tmpTrade = new BondTrade();
//依次赋值属性,需要赋值Trade本身的属性和BondTrade新增的属性
tmpTrade.NO = aTrade.NO;
tmpTrade.ORDCOUNT = aTrade.ORDCOUNT;
tmpTrade.BondAmount = (aTrade as BondTrade).BondAmount;
//每笔明细交易的ORDCOUNT必须平分
tmpTrade.ORDCOUNT = aTrade.ORDCOUNT / aSplitCount;
tmpTrades.Add(tmpTrade);
}
else if (aTrade is FutureTrade)
{
//如果交易是期货交易,创建新的期货对象实例
FutureTrade tmpTrade = new FutureTrade();
//依次赋值属性,需要赋值Trade本身的属性和FutureTrade新增的属性
tmpTrade.NO = aTrade.NO;
tmpTrade.ORDCOUNT = aTrade.ORDCOUNT;
tmpTrade.FutureAmount = (aTrade as FutureTrade).FutureAmount;
//每笔明细交易的ORDCOUNT必须平分
tmpTrade.ORDCOUNT = aTrade.ORDCOUNT / aSplitCount;
tmpTrades.Add(tmpTrade);
} }
return tmpTrades;
}

很容易看出上面代码的弊端:

1.SplitTrade方法本身应该是一个通用的拆分交易的方法,操作的是基类Trade,内部是不应该知道具体交易的。上面的代码中拆分交易的方法依赖了Trade的具体实现对象。

2.不利于扩展。如果新增一个交易类型,如回购交易,需要修改上面的代码。SplitTrade方法没有做到通用处理。

上面的问题其实就是:

SplitTrade方法本身,已经有了参数Trade(可能为BondTrade实例,或者FutureTrade实例,或者将来的**Trade实例 ),一个接口类型的交易对象实例,但是我们只知道这个参数是交易类型,并不知道是哪种交易,现在要新创建新的交易子类对象(如果前面是BondTrade实例,我还需要创建该实例,属性值同原来的BondTrade实例),相当于通过接口来创建对象。

原型模式就是解决这种问题的。

原型模式的本质:

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

这句话分为两点:

1.创建新的对象实例

2.为新的对象实例复制原型实例的属性值

原型模式通过一个原型实例来创建新的对象,不再关系这个实例本身的类型,也不关心他的具体实现,只要他自身实现了拷贝自己的方法即可(Clone)。通过该方法,就可以直接返回本身对象实例,不用在外面通过New去实现。

原型模式的组成:

ProtoType:定义一个Clone接口,使得继承他的子类都必须实现自己的Clone方法。即上文中的Trade。

ConcreteProtoTYpe:实现ProtoType类的Clone接口,通过Clone方法,可以新增一个对象,并把原始对象的属性赋值给新创建对象。即上文中的BondTrade、FutureTrade。

Client:使用原型方法的地方。通过一个原型实例,克隆自身来创建新的对象实例。即上文中的SplitTrade方法。

代码改进:

根据原型模式,我们对上面的代码进行改进,在Trade类中新增Clone方法(拷贝NO、ORDCOUNT等属性)。然后在BondTrade、FutureTrade方法重写Clone方法(拷贝BondAmount、FutureAmount等自身子类的属性)。

幸运的是,C#自身就有IClone接口和MemberwiseClone方法。在上面的例子中,只用在Trade基类中继承IClone接口,并且实现方法,方面里面简单调用MemberwiseClone即可。

修改后的SplitTrade方法变为:

/// <summary>
/// 拆分交易(使用原型模式)
/// </summary>
/// <param name="aTrade">原始交易</param>
/// <param name="aSplitCount">拆分的笔数</param>
public static List<Trade> SplitTradeWithProtoType(Trade aTrade, int aSplitCount)
{
List<Trade> tmpTrades = new List<Trade>(); if (aTrade == null)
{
return null;
} if (aSplitCount == 0)
{
tmpTrades.Add(aTrade);
return tmpTrades;
} for (int i = 0; i < aSplitCount; i++)
{
//直接调用Clone方法即可
Trade trade = aTrade.Clone() as Trade;
trade.ORDCOUNT = aTrade.ORDCOUNT / aSplitCount;
tmpTrades.Add(trade);
}
return tmpTrades;
}

补充描述:

1.Clone方法本身相当于New了一个对象。不同的是New一个对象实例,一般属性是没有值或者只有默认值。Clone出来的实例,通常属性是有值的,属性的值就要原型对象的属性值。

2.原型对象和克隆出来的对象。虽然说是拷贝出来的,但是指向是不同的,本质上还是不同的对象。

3.深克隆和浅克隆。

浅克隆,拷贝对象的所有值类型属性。

深克隆,除拷贝对象的所有值类型属性以外,还拷贝对象的所有引用类型,只是引用的

深克隆有个特点,就是如果属性的值是引用类型,会一直递归拷贝下去,知道拷贝到值类型为止。因此,要想深克隆拷贝成功,克隆过程中涉及的所有对象都要实现Clone方法,否则将会导致拷贝失败。

原型模式其实就是一个Clone方法,本质是克隆生成对象。

原型模式的好处是在调用时(如上面的SplitTrade方法),只知道接口类型(Trade),不知道具体的实现类型(BondTrade、FutureTrade),减少了使用方对这些具体实现的依赖。

设计模式-原型模式(Prototype)的更多相关文章

  1. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

  2. [工作中的设计模式]原型模式prototype

    一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...

  3. C#设计模式——原型模式(Prototype Pattern)

    一.概述 在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定.对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依 ...

  4. 设计模式——原型模式(Prototype Pattern)

    原型模式:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象. UML 图: 原型类: package com.cnblog.clarck; /** * 原型类 * * @author c ...

  5. 大话设计模式--原型模式 Prototype -- C++实现

    1. 原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象... 注意: 拷贝的时候是浅拷贝 还是 深拷贝, 来考虑是否需要重写拷贝构造函数. 关键在于: virtual Pro ...

  6. 设计模式——原型模式(Prototype)

    用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.——DP UML类图 模式说明 如果把在一张纸上手写一篇简历的过程看成是类的实例化过程,那么通过原型模式创建对象的过程就是拿着这张纸到复印 ...

  7. 设计模式--原型模式Prototype(创建型)

    一.原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.原型模式实现的关键就是实现Clone函数,还需要实现深拷贝. 二.UML类图 三.例子 //父类 class Resume ...

  8. 谈谈设计模式~原型模式(Prototype)

    返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式 ...

  9. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

随机推荐

  1. 辩护技巧总结——律师在刑事辩护中应注意的几个问题 z

    律师在刑事辩护中的角色就像医院中的医生对病人一样,对嫌疑人至关重要.律师的百分之一的失误,对嫌疑人来讲就是百分之百的不幸.因此我在刑事辩护中更加谨慎认真,并归纳了一些注意点供朋友参考.    一.仔细 ...

  2. DevExpress打印功能 z

    一.打印功能说明: 打印功能,我们有多种实现方式,可以根据需要自行选择,我简单的总结下两种方法. (1).使用微软.net框架自带的PrintDocument,这种方式是直接借助Graphics,自行 ...

  3. 第十章 Vim程序编辑器学习

    1.Vim是进阶版的vi,vim不但可以用不同颜色显示文字内容,还能进行诸如shell script,C program等程序编辑功能. 区别:vi是老师的字处理器,不过功能已经很齐全,但还是有可以进 ...

  4. Java 线程间通讯(管道流方式)

    一.管道流是JAVA中线程通讯的常用方式之一,基本流程如下: 1)创建管道输出流PipedOutputStream pos和管道输入流PipedInputStream pis 2)将pos和pis匹配 ...

  5. gomobile 真机 log 打出的日志跟踪

    go mobile 开发的应用,真机调试时,我们期望看到log包打出的日志, 这时候就需要借用 Android Device Monitor 了. 我们的 go 代码中用最简单的 log.Printl ...

  6. turing 项目引用

    1.友盟自动更新 2.友盟统计 3.友盟消息推送 http://www.bejson.com/json2javapojo/ 引用bejson 解析JSON生成类,数组 private List< ...

  7. C#中如何设置窗体的默认按钮和取消按钮

    可以直接在窗体的AcceptButton和CancelButton中设置相应的按钮. 也可以在后头通过代码设置: this.AcceptButton = (IButtonControl)btnSave ...

  8. Codeforces 519E A and B and Lecture Rooms [倍增法LCA]

    题意: 给你一棵有n个节点的树,给你m次询问,查询给两个点,问树上有多少个点到这两个点的距离是相等的.树上所有边的边权是1. 思路: 很容易想到通过记录dep和找到lca来找到两个点之间的距离,然后分 ...

  9. Loadrunner 添加windows资源没反应

    使用 LoadRunner Controller 添加Windows资源系统没有反应, 解决办法 : 1.关闭Windows 防火墙 2.若使用的不是本机 1) 首先要启动所监测机器的remote r ...

  10. 用imageNamed加载图片产生的问题

    通常我们会用imageNamed:来加载图片,但是用这个API有个问题,就是它会缓存加载的image. 因此,对于那些被重用的图片,这个API很高效.但是对于那些使用很少的图片,用这个就很耗内存,那怎 ...