设计模式之美: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 某个类的构造方法中 ...
随机推荐
- Excel的文件打开特别慢,xls文件特别大解决一例
Excel的文件打开特别慢,xls文件特别大解决一例 打开Excel的xls文件打开特别慢,而且操作也非常慢,动辄需要10几20分钟,很不正常.一个简单的Excel的xls文件有10几兆,甚至几百兆的 ...
- C#DataGridView中的常用技巧
0(最基本的技巧). 获取某列中的某行(某单元格)中的内容 this.currentposition = this.dataGridView1.BindingContext [this.dataG ...
- 【转】还html标签以本来意义
说句实话,“div+css”这个词汇不知道害了多少人,也许其提出者本意并没有错,但是跟风者从表现曲解了其意思,认为整个页面就应当是div+css文件的组合.这样做,对于视觉上并没有什么影响,因为还原了 ...
- 一段防盗连的PHP代码
$ADMIN[defaulturl] = http://www.163.com/404.htm; //盗链返回的地址 $okaysites = array("http://www.163 ...
- VMware下 Ubuntu 看不到共享文件夹之解决办法
VMware下 Ubuntu 看不到共享文件夹之解决办法 初学Linux,在VMWare 上装了Ubuntu10.04,主机端和虚拟机相互间的访问是必不可少的,途径有许多,其中vmware tool提 ...
- linux系统man命令用法和安装方法
Linux提供了丰富的帮助手册,当你需要查看某个命令的参数时不必到处上网查找,只要man一下即可. Linux的man手册共有以下几个章节: 代號 代表內容 1 使用者在shell中可以操作的指令或可 ...
- python学习之——小闹钟(持续完善ing)
"啊,坏了,我忘了那啥啥了~~~" 为了不坏了,动手做一个小闹钟吧,一点点完善的过程一定美好极了,必像等待培育许久的花儿绽放一样,不多说,加油,期待↖(^ω^)↗ #! /usr/ ...
- mysql root 密码丢失问题
root密码丢失,我们需要将mysql以不检查权限的方式重新启动. 在mysql的配置文件(/etc/my.cnf)中,[mysqld]下添加一句skip-grant-tables,然后重新启动服务, ...
- 记录一个多核CPU负载不均衡问题(动态绑定进程到指定cpu:taskset -pc $CPU $PID)
昨晚和一位读者朋友讨论了一个问题:在一台多核 CPU 的 Web 服务器上,存在负载不均衡问题,其中 CPU0 的负载明显高于其它 CPUx,进一步调查表明 PHP-FPM 的嫌疑很大.话说以前我曾经 ...
- [python] 线程池
特别感谢simomo 什么是线程池? 诸如web服务器.数据库服务器.文件服务器和邮件服务器等许多服务器应用都面向处理来自某些远程来源的大量短小的任务.构建服务器应用程序的一个过于简单的模型是:每当一 ...