设计模式之美:Prototype(原型)
索引
别名
- 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 操作。当内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能也会很困难。
效果
- 它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。
- 使客户无需改变即可使用与特定应用相关的类。
- 运行时刻增加和删除产品。
- 改变值以指定新对象。
- 改变结构以指定新对象。
- 减少子类的构造。
- 用类动态配置应用。
相关模式
- Abstract Factory 可以用 Prototype来实现。
- Composite和 Decorator模式的设计也可以从 Prototype 获益。
命名约定
使用命名约定是一个好习惯,例如,总是声明那些实现克隆的操作为 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(原型)的更多相关文章
- 设计模式05: Prototype 原型模式(创建型模式)
Prototype 原型模式(创建型模式) 依赖关系的倒置抽象不应该依赖于实现细节,细节应该依赖于抽象.对所有的设计模式都是这样的. -抽象A直接依赖于实现细节b -抽象A依赖于抽象B,实现细节b依赖 ...
- 面向对象设计模式纵横谈:Prototype 原型模式(笔记记录)
有一段时间没写东西了,今天继续把没写完的设计模式写完,今天这堂课是创建型设计模式的最后一堂课,原型设计模式,它同样也是解决了对象在创建的过程中的解耦合的情况,面对变化使代码更稳定,更准确的说是使 ...
- C#面向对象设计模式纵横谈——6.Prototype 原型模式(创建型模式)
动机(Motivation) 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作.由于需求的变化,这些对象经常面临着剧烈的变化,但他们却拥有比较稳定一致的接口. 如何应对这种变化?如何向“客户程 ...
- 设计模式学习笔记——Prototype原型模式
原型模型就是克隆. 还有深克隆.浅克隆,一切听上去都那么耳熟能详.
- PHP设计模式(六)原型模式(Prototype For PHP)
原型设计模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型设计模式简单的来说,顾名思义, 不去创建新的对象进而保留原型的一种设计模式. 缺点:原型设计模式是的最主要的缺点就 ...
- 小菜学习设计模式(四)—原型(Prototype)模式
前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...
- 设计模式学习系列6 原型模式(prototype)
原型模式(prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.允许一个对象再创建另外一个新对象的时候根本无需知道任何创建细节,只需要请求圆形对象的copy函数皆可. 1 ...
- 设计模式(四)原型模式Prototype(创建型)
设计模式(四)原型模式Prototype(创建型) 1. 概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...
- 设计模式:Prototype 原型模式 - 同学你抄过别人的作业么?-clone()方法的使用
原型模式: 通过某个类的实例来创建对象 使用原型模式的好处: 好处是什么呢?当我们需要多次重复的创建一个类的示例的时候,我们可以使用new但是,new不仅仅耗费内存而且,如果new 某个类的构造方法中 ...
随机推荐
- Lock锁的使用示例
Lock锁是java5用来代替synchronized的一种面向对象的锁的方案 public class LockDemo { /** * Lock是用来替换synchronized, 优点是Lock ...
- [翻译]Shape comparison language[转]
link: http://www.cnblogs.com/yhlx125/p/3635623.html Shape comparison language 首先说说我遇到的一个问题: IR ...
- TinyXML:一个优秀的C++ XML解析器
//-------------------------------------------------------------------------------------------------- ...
- python之路-Day1
Python 是一门什么样的语言? python是一门动态解释性的强类型定义语言 动态语言:动态类型语言是指在运行期间才去做数据类型检查的语言,也就是说,在用动态类型的语言编程时,永远也不用给任何变量 ...
- 【MVC】 基础
[MVC] 基础 一. Controller ActionResult ContentResult 返回string类型 EmptyResult 空 FileContentResult ...
- laravel遇到的问题
这是由于访问laravel项目报错的,解决几种可能出现的错误. 1)打开:D:\java\wamp\www\subway\app\config\app.php 修改:'debug' => tru ...
- ubuntu 16.04软件源
来源:模板:16.04source deb http://cn.archive.ubuntu.com/ubuntu/ xenial main restricted universe multive ...
- centos 添加 composer
下载安装包 curl -sS https://getcomposer.org/installer | php 把 composer 把复制到 /usr/bin/composer mv composer ...
- Android消息机制:Looper,MessageQueue,Message与handler
Android消息机制好多人都讲过,但是自己去翻源码的时候才能明白. 今天试着讲一下,因为目标是讲清楚整体逻辑,所以不追究细节. Message是消息机制的核心,所以从Message讲起. 1.Mes ...
- html、css、js文件加载顺序及执行情况
HTML页面加载和解析流程 1. 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件. 2. 浏览器开始载入html代码,发现<head& ...