索引

别名

  • 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. session基础

    1.每个页面都必须开启session_start()后才能在每个页面里面使用session. 2.session_start()初始化session,第一次访问会生成一个唯一会话ID保存在客户端(是基 ...

  2. 2.Mybatis入门程序(单表的增删改成)

    这里讲的单表的增删改查,是由mapper代理的增删改查,先来看看步骤: 1.jar包的导入 2.配置全局的配置文件 3.建立接口 4.编写mapper.xml 5.测试 工程结构:这个你们自己可以调整 ...

  3. Windows 窗体设计器中的设计时错误

    当修改窗体里面某一项时导致窗体报错,但是编译运行没问题,报"依赖项问题"则只需要把报错的那个依赖项删除后再重新引用.

  4. PHPMyadmin 配置文件详解(配置)

    PHPMyadmin配置文件config.inc.php内容如下,在需要设置的地方增加了相关注释. 非常适合对数据库操作命令不熟悉的数据库管理者,下面我就说下怎么安装该工具: 1.先到网上下载phpm ...

  5. linux 下搭建 storm

    搭建storm  需要搭建: 1.zookeeper 搭建 2.下载/安装 storm 的依赖包  zeromq, jzmq,python 2.storm 搭建 一.Zookeeper 安装 下载安装 ...

  6. 扩展Smack Message

    XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性. Smack是一个开源的用 java 写的XMPP(jabber)客户端代码库 因为XMPP是XML,所以进行 ...

  7. Eclipse 3.5使用dropins的插件安装方式

    以前安装Eclipse插件有两种方式 1 直接copy插件到features/plugins目录 2 在links目录下创建链接文件. 而 Eclipse 3.5又推出另一种新的安装途径, 更加灵活. ...

  8. delphi日期格式化免操作系统依赖单元

    delphi免操作系统依赖单元 经常在windows里面,我们需要yyyy-mm-dd格式日期,可是用户却没有设置成这个 格式,而用程序去修改用户的日期格式设置,是不明智的,将影响其他程序的运行. 本 ...

  9. github的一些指令

  10. RNN and LSTM saliency Predection Scene Label

    http://handong1587.github.io/deep_learning/2015/10/09/rnn-and-lstm.html  //RNN and LSTM http://hando ...