您的位置:首页 > 其它

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

2014-02-12 09:51 337 查看

前言

设计模式目录:

小菜学习设计模式(一)—模板方法(Template)模式

小菜学习设计模式(二)—单例(Singleton)模式

小菜学习设计模式(三)—工厂方法(Factory Method)模式

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

小菜学习设计模式(五)—控制反转(Ioc)

持续更新中。。。

本篇目录:

概述

实现

深拷贝(Deep Copy)

后记

  其实说到原型模式,大家可能会想到Clone,其实也不尽然,在我们的日常生活中,原型(Prototype)模式也可以经常看到:

你觉得某位明星的发型很好看,你也想做个和他一样的发型,于是你拿个照片去理发店说:我要做个和这个一模一样的发型。

  其实那个明星的发型某种意义上说就是原型,因为已经有发型参考了,所以发型师会很快的做出来。就像我们在编程时,当创建一些对象(特别是大对象)非常耗时时,或者创建过程非常复杂时,原型模式就会很有用。

概述

  我们看下GoF对原型(Prototype)模式下的定义:

使用原型模型实例指定将要创建的对象类型,通过复制这个实例创建新的对象。

  从这个定义中,我们可以分解下,其实说的意思就是:指定类型,复制对象。就像上面的例子,造型就是一个指定的类型,然后去复制此类型的对象。原型模型的简单静态类图:

/// <summary>
/// 心脏类
/// </summary>
public class Heart
{
private int _size;
private int _volume;
/// <summary>
/// 大小
/// </summary>
public int Size
{
get { return _size; }
set { _size = value; }
}
/// <summary>
/// 体积
/// </summary>
public int Volume
{
get { return _volume; }
set { _volume = value; }
}
}

/// <summary>
/// baby类
/// </summary>
public class Baby : ICloneable
{
private string _name;
private string _description;
private Heart _hearttype;
/// <summary>
/// 名称
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// 描述
/// </summary>
public string Description
{
get { return _description; }
set { _description = value; }
}
/// <summary>
/// 心脏特征
/// </summary>
public Heart HeartType
{
get { return _hearttype; }
set { _hearttype = value; }
}

#region ICloneable 成员
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}


View Code
  测试代码:

static void Main(string[] args)
{
Baby baby1 = new Baby();
baby1.Name = "I'm baby1";
baby1.Description = "I'm baby";
baby1.HeartType = new Heart() { Size = 111, Volume = 222 };
Baby baby2 = (Baby)baby1.Clone();
baby2.Name = "I'm baby2";

Console.WriteLine("baby1 info:");
Console.WriteLine(baby1.Name);
Console.WriteLine(baby1.Description);
Console.WriteLine("baby2 info:");
Console.WriteLine(baby2.Name);
Console.WriteLine(baby2.Description);
Console.WriteLine("The heart of the different:");
Console.WriteLine(baby1.HeartType == baby2.HeartType);
}


  运行结果:



  我们可以看到baby1.HeartType和baby2.HeartType的引用地址是一样的,这种就是浅拷贝(Shallow Copy),就说明baby1和baby2公用一个心脏,是连体双胞胎。

深拷贝(Deep Copy)

  其实上面的代码稍微修改下就是深拷贝,如下:

static void Main(string[] args)
{
Baby baby1 = new Baby();
baby1.Name = "I'm baby1";
baby1.Description = "I'm baby";
baby1.HeartType = new Heart() { Size = 111, Volume = 222 };
Baby baby2 = (Baby)baby1.Clone();
baby2.HeartType = new Heart() { Size = 111, Volume = 222 };//重新创建对象
baby2.Name = "I'm baby2";

Console.WriteLine("baby1 info:");
Console.WriteLine(baby1.Name);
Console.WriteLine(baby1.Description);
Console.WriteLine("baby2 info:");
Console.WriteLine(baby2.Name);
Console.WriteLine(baby2.Description);
Console.WriteLine("The heart of the different:");
Console.WriteLine(baby1.HeartType == baby2.HeartType);
}


  上面给baby2重新创建一个和baby1一样的心脏,而不是公用一个,运行结果:



  可以看到baby1.HeartType和baby2.HeartType的引用地址是不一样的,虽然是一样的心脏,但是是两个独立相同的心脏,其实上面的方法并不算是深拷贝,只是实现了深拷贝的效果,因为并不是在拷贝中完成的。这种气势有个不好的地方,当一个对象中有很多对象组合的时候,而且这个对象内部很复杂,我们不可能复制完之后,每个对象的去重新赋值,这样实现深拷贝就没有什么意义。当然还有一种实现深拷贝的方式就是序列化,必须在类的前面加上[Serializable]表示,指示这个类是可以序列化的,我们把Clone()的方法修改下:

public object Clone()
{
object result = null;
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Close();
byte[] streamByte = stream.ToArray();
MemoryStream stream2 = new MemoryStream(streamByte);
result = formatter.Deserialize(stream2);
stream2.Close();
return result;
}


  现在Clone()方法做的工作就是序列化和反序列化,我们使用浅拷贝的测试代码,运行结果为:



  baby1.HeartType和baby2.HeartType的引用地址是不一样的,和上面重新赋值对象的效果是一样的,但是我们调用的时候没有做额外的操作,就可以实现此效果,但是序列化和反序列化是比较耗时的,这点也需要注意下。

  示例代码下载:Prototype.rar

后记

  关于创建型模式上面几篇说的差不多,还有个针对工厂方法模式出现问题的解决方案,下面就是结构型模式了,还在学习中,未完待续。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: