分类:创建型模式
一、应用场景
在一个特定的场景中经常需要出现多个相同但状态各异的对象,通常的解决方法是通过new创建这些对象之后分别去设置这些对象的状态。原型设计模式提供了更快捷、更有效的解决方法。
二、意图
通过复制(克隆、拷贝)一个指定类型的对象来创建更多同类型的对象。这个指定的对象可被称为“原型”对象,也就是通过复制原型对象来得到更多同类型的对象。
三、关于拷贝
在C#中,拷贝一个对象可以调用对象的clone()方法,如果其实现了ICloneable接口。对象的拷贝分为两种:深拷贝与浅拷贝。所谓深拷贝指的是拷贝出来的对象与原有对象不共享任何数据,这里可以假设一个对象含有一个引用类型的字段A,那么拷贝出来的新对象与原有对象的字段A分别指向不同内存位置,也就是说修改新对象的字段A不会影响原对象的字段A(新对象与原有对象除了类型相同之外没有任何关系)。浅拷贝则不然,如果一个对象中含有一个引用类型的字段A,那么在通过浅拷贝得到新对象之后,新对象与原对象的字段A指向的是同一个内存位置,显然,对新对象字段A的修改必定要影响原对象的字段A,这可以说是原型设计模式最关键的部分。
在.net中提供了一个MemberwiseClone()方法,这个方法用于实现对象的浅拷贝。但如果想实现对象的深拷贝,则类必须实现ICloneable接口并重写clone()方法。
原型设计模式就是利用对象的“拷贝”来解决特定场景下的对象创建工作。
四、结构与角色:(见附件图11)
角色:
客户:使用原型对象的客户程序
抽象原型(抽象产品):规定了具体原型对象必须实现的接口(如果要提供深拷贝,则必须具有实现ICloneable的规定)
具体原型(具体产品):从抽象原型派生而来,是客户程序使用的对象。
五、代码示例(这里只指供浅拷贝实现)
/// <summary>
/// 抽象原型
/// </summary>
public abstract class Car
{
public Car()
{
//...
}
public abstract string CarName
{
get ;
set ;
}
public abstract string Location
{
get ;
set ;
}
public abstract object Clone();
}
//具体原型(这是奥迪车)
public class AudiCar : Car
{
private string _carName = "奥迪" ;
private string _location = "" ;
public AudiCar()
{
//...
}
public override string CarName
{
get
{
return _carName ;
}
set
{
_carName = value ;
}
}
public override string Location
{
get
{
return _location ;
}
set
{
_location = value ;
}
}
public override object Clone()
{
return this.MemberwiseClone() ;
}
}
//具体原型(这宝马车)
public class BMWCar : Car
{
private string _carName = "宝马" ;
private string _location = "" ;
public BMWCar()
{
//...
}
public override string CarName
{
get
{
return _carName ;
}
set
{
_carName = value ;
}
}
public override string Location
{
get
{
return _location ;
}
set
{
_location = value ;
}
}
public override object Clone()
{
return this.MemberwiseClone() ;
}
}
客户调用:
//创建对象
BMWCar tBMWCar = new BMWCar() ;
tBMWCar.Location = "中国" ;
tBMWCar.CarName = "宝马A" ;
//拷贝对象
BMWCar tBMWCar1 = (BMWCar)tBMWCar.Clone() ;
//设置新对象属性
tBMWCar1.CarName = "宝马B" ;
Response.Write( tBMWCar.CarName + "在" + tBMWCar.Location + "<br>") ;
Response.Write(tBMWCar1.CarName + "在" + tBMWCar1.Location ) ;
运行结果:
宝马A在中国
宝马B在中国
不难理解,如果需要同类型但不同状态的对象时,可以Clone,这样,在新的对象产生后只需要根据情况设置新对象状态即可。(这里,新对象利用了原对象的部分状态,可以说这是原型的特点,即动态获取对象状态)
六、带原型管理器的原型设计模式
这是原型设计模式的另一种使用方式,它比我们上面要多一种角色
原型管理器角色(Prototype Manager):该角色用于创建具体的原型类对象,并且把已经创建过的对象保存下来。说白了就是先创建对象并将其保存下来(由管理器完成)然后利用Clone()方法来创建新对象。
结构图为:(见附件图22)
代码如下:
/**
* Design Pattern In Java
* Name:Prototype
* 目的:利用Prototype创建一批同样的产品
* 原型:PrototypeRam
* 拷贝:ClonedRam
* P:Prototype
* C:Clone
* Author:blackphoenix
* Modify Date:2002-08-18
*/
import java.util.*;
/**
* 定义原型产品类 PrototypeRam
* 此类即后面用来产品大量产品的模板
*/
class PrototypeRam implements Cloneable {
String name;
public PrototypeRam() {
name="Hi,I am PrototypeRam!";
}
public Object clone() {
Object o=null;
try {
o=super.clone();
}
catch(CloneNotSupportedException e) {
System.err.println("PrototypeRam is not cloneable!");
}
return o;
}
}
/**
* 原型管理器,用来方便地对原型进行管理
* 可以实现自动注册原形的功能
* 由于原型管理器运行时只要一个实例,所以用单态实现它
*/
class PrototypeManager {
private static PrototypeManager pm;
Hashtable prototypes=null;
private PrototypeManager() {
prototypes=new Hashtable();
}
public static PrototypeManager getManager() {
if(pm==null) {
pm=new PrototypeManager();
}
return pm;
}
public void register(String name,Object prototype) {
prototypes.put(name,prototype);
}
public void unregister(String name) {
prototypes.remove(name);
}
public Object getPrototype(String name) {
if(prototypes.containsKey(name)) {
return prototypes.get(name);
}else {
Object o=null;
try {
/**
* 自动查找原型管理器里不存在的类,并动态生成它
*/
o=Class.forName(name).newInstance();
register(name,o);
}
catch(Exception e) {
System.err.println("Class "+name+"没有定义!");
}
return o;
}
}
}
/**
* 客户端代码,使用PrototypeManager获得原型
* 通过PrototypeRam生成一批Ram
*/
public class Prototype {
PrototypeManager pm=null;
public Prototype() {
pm=PrototypeManager.getManager();
}
public static void main(String[] args) {
String classname=null;
classname=args[0];
Prototype test=new Prototype();
PrototypeRam pRam=(PrototypeRam)(test.pm.getPrototype(classname));
if(pRam!=null) {
PrototypeRam[] cRam;
System.out.println("PrototypeRam: "+pRam.name);
cRam=new PrototypeRam[10];
for(int i=0;i<10;i++) {
/**
* 生成一批克隆的Ram,并比较他们和原型的不同
*/
cRam[i]=(PrototypeRam)pRam.clone();
System.out.println("Cloned Ram"+i+": "+pRam.name);
}
}else {
System.err.println("Sorry,can't find the class!");
}
}
}