索引

别名

  • Clone

意图

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

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

结构

参与者

Prototype

  • 声明一个克隆自身的接口。

ConcretePrototype

  • 实现一个克隆自身的操作。

Client

  • 让一个原型克隆自身从而创建一个新的对象。

适用性

在以下情况下可以使用 Prototype 模式:

  • 一个系统要独立于它的产品的创建、构成和表示时。
  • 当要实例化的类是在运行时刻指定时,例如:通过动态装载。
  • 为了避免创建一个与产品类层次平行的工厂类层次时。
  • 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

缺点

  • 每一个 Prototype 子类都必须实现 Clone 操作。当内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能也会很困难。

效果

  • 它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。
  • 使客户无需改变即可使用与特定应用相关的类。
  • 运行时刻增加和删除产品。
  • 改变值以指定新对象。
  • 改变结构以指定新对象。
  • 减少子类的构造。
  • 用类动态配置应用。

相关模式

命名约定

使用命名约定是一个好习惯,例如,总是声明那些实现克隆的操作为 Clone()。

实现

实现方式(一):使用一个原型管理器。

当一个系统中原型数目不固定时,可以保持一个可用原型的注册表,用以存储和检索原型。我们称这个注册表为原型管理器(Prototype Manager)。

客户在克隆一个原型前会先向注册表请求该原型。

 namespace PrototypePattern.Implementation1
{
public abstract class AbstractOrInterfaceOfPrototypeProduct
{
public int ValueProperty1 { get; set; } public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
} public class ConcretePrototypeProductA : AbstractOrInterfaceOfPrototypeProduct
{
public override AbstractOrInterfaceOfPrototypeProduct Clone()
{
return new ConcretePrototypeProductA()
{
ValueProperty1 = this.ValueProperty1,
};
}
} public class ConcretePrototypeProductB : AbstractOrInterfaceOfPrototypeProduct
{
public override AbstractOrInterfaceOfPrototypeProduct Clone()
{
return new ConcretePrototypeProductB()
{
ValueProperty1 = this.ValueProperty1,
};
}
} public class ProductPrototypeManager
{
private Dictionary<string, AbstractOrInterfaceOfPrototypeProduct> _registry
= new Dictionary<string, AbstractOrInterfaceOfPrototypeProduct>(); public void Register(string name,
AbstractOrInterfaceOfPrototypeProduct prototypeProduct)
{
_registry[name] = prototypeProduct;
} public void Unregister(string name)
{
_registry.Remove(name);
} public AbstractOrInterfaceOfPrototypeProduct Retrieve(string name)
{
return _registry[name];
} public bool IsRegisterd(string name)
{
return _registry.ContainsKey(name);
}
} public class Client
{
public void TestCase1()
{
AbstractOrInterfaceOfPrototypeProduct prototypeProduct1 = new ConcretePrototypeProductA();
AbstractOrInterfaceOfPrototypeProduct prototypeProduct2 = new ConcretePrototypeProductB(); ProductPrototypeManager manager = new ProductPrototypeManager();
manager.Register("PrototypeProduct1", prototypeProduct1);
manager.Register("PrototypeProduct2", prototypeProduct2); AbstractOrInterfaceOfPrototypeProduct clonedProduct1 = manager.Retrieve("PrototypeProduct1").Clone(); if (manager.IsRegisterd("PrototypeProduct2"))
{
AbstractOrInterfaceOfPrototypeProduct clonedProduct2 = manager.Retrieve("PrototypeProduct2").Clone();
}
}
}
}

实现方式(二):使用浅拷贝实现克隆(Clone)操作。

Prototype 模式最困难的部分在于正确的实现 Clone 操作。

浅拷贝(Shallow Copy)在拷贝时只复制对象所有字段的值。如果字段是值类型,则复制其值;如果字段是引用类型,则复制引用指针。

 namespace PrototypePattern.Implementation2
{
public class ReferencedClass
{
public int ReferencedClassProperty1 { get; set; }
} public abstract class AbstractOrInterfaceOfPrototypeProduct
{
public int ValueProperty1 { get; set; }
public ReferencedClass ReferenceProperty2 { get; set; } public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
} public class ConcreteShallowCopyPrototypeProductA
: AbstractOrInterfaceOfPrototypeProduct
{
public ConcreteShallowCopyPrototypeProductA()
{
this.ReferenceProperty2 = new ReferencedClass()
{
ReferencedClassProperty1 =
};
} public override AbstractOrInterfaceOfPrototypeProduct Clone()
{
return new ConcreteShallowCopyPrototypeProductA()
{
ValueProperty1 = this.ValueProperty1,
ReferenceProperty2 = this.ReferenceProperty2,
};
}
} public class Client
{
public void TestCase2()
{
AbstractOrInterfaceOfPrototypeProduct prototypeProduct1 = new ConcreteShallowCopyPrototypeProductA();
AbstractOrInterfaceOfPrototypeProduct clonedProduct1 = prototypeProduct1.Clone();
bool areEqual1 = object.ReferenceEquals(
prototypeProduct1.ReferenceProperty2,
clonedProduct1.ReferenceProperty2);
}
}
}

实现方式(三):使用深拷贝实现克隆(Clone)操作。

深拷贝(Deep Copy)涉及对源对象整个结构的拷贝。

深拷贝在拷贝时复制对象的所有字段的值。如果字段是值类型,则复制其值;如果字段是引用类型,则会将这个引用指针指向的对象也克隆一份。

可以通过序列化和反序列化来实现深拷贝。

 namespace PrototypePattern.Implementation3
{
public class ReferencedClass
{
public int ReferencedClassProperty1 { get; set; }
} public abstract class AbstractOrInterfaceOfPrototypeProduct
{
public int ValueProperty1 { get; set; }
public ReferencedClass ReferenceProperty2 { get; set; } public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
} public class ConcreteShallowCopyPrototypeProductA
: AbstractOrInterfaceOfPrototypeProduct
{
public ConcreteShallowCopyPrototypeProductA()
{
this.ReferenceProperty2 = new ReferencedClass()
{
ReferencedClassProperty1 =
};
} public override AbstractOrInterfaceOfPrototypeProduct Clone()
{
return new ConcreteShallowCopyPrototypeProductA()
{
ValueProperty1 = this.ValueProperty1,
ReferenceProperty2 = this.ReferenceProperty2,
};
}
} public class ConcreteDeepCopyPrototypeProductB
: AbstractOrInterfaceOfPrototypeProduct
{
public ConcreteDeepCopyPrototypeProductB()
{
this.ReferenceProperty2 = new ReferencedClass()
{
ReferencedClassProperty1 =
};
} public override AbstractOrInterfaceOfPrototypeProduct Clone()
{
return new ConcreteDeepCopyPrototypeProductB()
{
ValueProperty1 = this.ValueProperty1,
ReferenceProperty2 = new ReferencedClass()
{
ReferencedClassProperty1 =
this.ReferenceProperty2.ReferencedClassProperty1
},
};
}
} public class Client
{
public void TestCase3()
{
AbstractOrInterfaceOfPrototypeProduct prototypeProduct1 = new ConcreteShallowCopyPrototypeProductA();
AbstractOrInterfaceOfPrototypeProduct clonedProduct1 = prototypeProduct1.Clone();
bool areEqual1 = object.ReferenceEquals(
prototypeProduct1.ReferenceProperty2,
clonedProduct1.ReferenceProperty2); AbstractOrInterfaceOfPrototypeProduct prototypeProduct2 = new ConcreteDeepCopyPrototypeProductB();
AbstractOrInterfaceOfPrototypeProduct clonedProduct2 = prototypeProduct2.Clone();
bool areEqual2 = object.ReferenceEquals(
prototypeProduct2.ReferenceProperty2,
clonedProduct2.ReferenceProperty2); Console.WriteLine("{0}, {1}", areEqual1, areEqual2);
}
}
}

实现方式(四):初始化克隆对象。

客户可能会希望使用一些值来初始化该对象的内部状态。

但在 Clone 操作中传递参数会破坏克隆接口的统一性。

原型的类可以在 Clone 操作之后,调用包含初始化参数的 Initialize 方法来设定对象内部状态。

 namespace PrototypePattern.Implementation4
{
public class ReferencedClass
{
public int ReferencedClassProperty1 { get; set; }
} public abstract class AbstractOrInterfaceOfPrototypeProduct
{
public int ValueProperty1 { get; set; }
public ReferencedClass ReferenceProperty2 { get; set; } public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
} public class ConcreteDeepCopyPrototypeProductB
: AbstractOrInterfaceOfPrototypeProduct
{
public ConcreteDeepCopyPrototypeProductB()
{
} public void Initialize(int propertyValue)
{
this.ValueProperty1 = propertyValue;
this.ReferenceProperty2.ReferencedClassProperty1 = propertyValue;
} public override AbstractOrInterfaceOfPrototypeProduct Clone()
{
return new ConcreteDeepCopyPrototypeProductB()
{
ValueProperty1 = this.ValueProperty1,
ReferenceProperty2 = new ReferencedClass()
{
ReferencedClassProperty1 =
this.ReferenceProperty2.ReferencedClassProperty1
},
};
}
} public class Client
{
public void TestCase4()
{
AbstractOrInterfaceOfPrototypeProduct prototypeProduct2 = new ConcreteDeepCopyPrototypeProductB();
ConcreteDeepCopyPrototypeProductB clonedProduct2 =
(ConcreteDeepCopyPrototypeProductB)prototypeProduct2.Clone(); clonedProduct2.Initialize();
}
}
}

设计模式之美》为 Dennis Gao 发布于博客园的系列文章,任何未经作者本人同意的人为或爬虫转载均为耍流氓。

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

  1. 设计模式05: Prototype 原型模式(创建型模式)

    Prototype 原型模式(创建型模式) 依赖关系的倒置抽象不应该依赖于实现细节,细节应该依赖于抽象.对所有的设计模式都是这样的. -抽象A直接依赖于实现细节b -抽象A依赖于抽象B,实现细节b依赖 ...

  2. 面向对象设计模式纵横谈:Prototype 原型模式(笔记记录)

       有一段时间没写东西了,今天继续把没写完的设计模式写完,今天这堂课是创建型设计模式的最后一堂课,原型设计模式,它同样也是解决了对象在创建的过程中的解耦合的情况,面对变化使代码更稳定,更准确的说是使 ...

  3. C#面向对象设计模式纵横谈——6.Prototype 原型模式(创建型模式)

    动机(Motivation) 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作.由于需求的变化,这些对象经常面临着剧烈的变化,但他们却拥有比较稳定一致的接口. 如何应对这种变化?如何向“客户程 ...

  4. 设计模式学习笔记——Prototype原型模式

    原型模型就是克隆. 还有深克隆.浅克隆,一切听上去都那么耳熟能详.

  5. PHP设计模式(六)原型模式(Prototype For PHP)

    原型设计模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型设计模式简单的来说,顾名思义, 不去创建新的对象进而保留原型的一种设计模式. 缺点:原型设计模式是的最主要的缺点就 ...

  6. 小菜学习设计模式(四)—原型(Prototype)模式

    前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...

  7. 设计模式学习系列6 原型模式(prototype)

    原型模式(prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.允许一个对象再创建另外一个新对象的时候根本无需知道任何创建细节,只需要请求圆形对象的copy函数皆可. 1 ...

  8. 设计模式(四)原型模式Prototype(创建型)

      设计模式(四)原型模式Prototype(创建型) 1.   概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...

  9. 设计模式:Prototype 原型模式 - 同学你抄过别人的作业么?-clone()方法的使用

    原型模式: 通过某个类的实例来创建对象 使用原型模式的好处: 好处是什么呢?当我们需要多次重复的创建一个类的示例的时候,我们可以使用new但是,new不仅仅耗费内存而且,如果new 某个类的构造方法中 ...

随机推荐

  1. Add Binary <leetcode>

    Given two binary strings, return their sum (also a binary string). For example,a = "11"b = ...

  2. PHP中,文件上传实例

    PHP中,文件上传一般是通过move_uploaded_file()来实现的.  bool move_uploaded_file ( string filename, string destinati ...

  3. VC++ 限制窗口的大小范围的方法

    响应WM_GETMAXMININFO  的消息 处理之 void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { // TODO: Add y ...

  4. python之路-Day1

    Python 是一门什么样的语言? python是一门动态解释性的强类型定义语言 动态语言:动态类型语言是指在运行期间才去做数据类型检查的语言,也就是说,在用动态类型的语言编程时,永远也不用给任何变量 ...

  5. hello

    #include <iostream> int main() { std::cout << "请输入两个数字:" << std::endl; , ...

  6. ArrayEasyFinish

    (1)Plus One 解题思路:模拟现实中做加法的方式,在个位加一,并考虑进位的情况.代码如下: public class Solution { public int[] plusOne(int[] ...

  7. Diagramming for WinForms 的安装和配置

    Diagramming for WinForms 是MindFusion公司推出的商业版通用流程图控件. 运行环境: WIN7 + .Net4.0 + Visual2010 试用版控件下载地址:htt ...

  8. JVM调优-Java垃圾回收之分代回收

    为什么要进行分代回收? JVM使用分代回收测试,是因为:不同的对象,生命周期是不一样的.因此不同生命周期的对象采用不同的收集方式. 可以提高垃圾回收的效率. Java程序运行过程中,会产生大量的对象, ...

  9. 利用Lambda获取属性名称

    感谢下面这篇博文给我的思路: http://www.cnblogs.com/daimage/archive/2012/04/10/2440186.html 上面文章的博主给出的代码是可用的,但是调用方 ...

  10. T60上安装Gentoo笔记

    T60虽然已经很老了,也过了服役期限.但是从入手之后,相比与家里放着的几个其他的高配置"后辈",依然是手中的挚爱.4:3的屏幕,方方正正的内敛模型,很结实的钢筋铁骨,无论是性格还是 ...