大话设计模式之原型模式

来源:互联网 发布:达内 测计网络营 编辑:程序博客网 时间:2024/05/17 04:02

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

 

 

 

原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节,基本代码如下:

 

//原型类abstractclass Prototype{         private string id;         public Prototype(string id)         {                   this.id = id;         }          public string Id()         {                   get{ retrun id; }         }                                                                                              //抽象类关键就是有这样一个Clone方法         public abstract Prototype Clone(); }; //具体原型类classConcretPrototype1 :Prototype{         public ConcretPrototype1(string id) :base(id)         {         }          public override Prototype Clone()         {                                                                                             //https://msdn.microsoft.com/zh-cn/library/system.object.memberwiseclone.aspx                                                                                             //MemberwiseClone方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。                                                                                             //如果字段是值类型的,则对该字段执行逐位复制。 如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。                   return (Prototype)this.MemberwiseClone();         } }; //客户端代码voidmain(){         ConcretPrototype1 p1 = new ConcretPrototype1("I");         ConcretPrototype1 c1 = (ConcretPrototype1)p1.Clone();                //克隆类 ConcretPrototype1 的对象p1就能得到新的实例c1}


 

 

其实,原型抽象类Prototype是用不着的。

因为,克隆实在是太常用了,.Net提供了ICloneable接口,其中唯一的方法就是Clone(), 这样只要实现这个接口就可以完成原型模式了

 

 

 

下面给出一个实例:

 

原题是需要给出几份相同的简历,但是我觉得有些牵强,于是就把题目改为生成几额类似的矩形,可以有细节上的差异。(虽然我把原题的代码结构图贴上来了)

 

 

 

classRectangle :ICloneable{         private int length;         private int width;         private string color;         private string birthtime;         private string author;          public Rectangle(string author)         {                   this.author = author;         }          //detail infomation         public void SetTangleInfo(int length, intwidth, string color)         {                   this.length = length;                   this.width = width;                   this.color = color;         }          //set create time         public void SetTime(string birthtime)         {                   this.birthtime = birthtime;         }          //show         public void Display()         {                   Console.WriteLine("{0}{1} {2}", length, width, color);                   Console.WriteLine("CreateTime : {0}, Author : {1} ", birthtime, author);         }          public Object Clone         {                   return (Object)this.MemberwiseClone();         }}; //客户端voidmain(){         Rectangle a = new Rectangle("Ben");         a.SetTangleInfo(10,20,"red");         a.SetTime("201504091049");                                                                                     //只需要调用Clone方法就可以实现新矩形的生成,并且可以修改新矩形的细节         Rectangle b = (Rectangle)a.Clone();         b.SetTime("201504091050");          Rectangle c = (Rectangle)a.Clone();         c.SetTangleInfo(20,10,"blue");          a.Display();         b.Display();         c.Display();}


 

 

这样一来,如果每个细节都一样,那么我们的代码可以显得十分清爽。

性能也得到了提高,比如看对象a的初始化,假设是复杂的项目,如果每个对象都这样,那么就太低效了。

一般在初始化信息不发生变化的情况下,克隆是最好的办法。这既隐藏了对象创建的细节,又对性能是大大的提高。

相当于是不用重新初始化对象,而是动态的获得对象运行时的状态。

 

 

 

但是,我们也发现,我们使用的MemberwiseClone() 函数,根据描述是浅拷贝,这里再把那段话拿过来看看:

 

【https://msdn.microsoft.com/zh-cn/library/system.object.memberwiseclone.aspx

MemberwiseClone方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。

如果字段是值类型的,则对该字段执行逐位复制。 如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。】

 

当前矩形类中的数据都是值类型(int,string),所以没有什么问题,但是如果类中有对象引用,那么引用的对象数据是不会被克隆过来的。

 

接下来我们修改一下矩形类,让其中的时间类型不再是string类型而是一个类。那么在使用的时候就需要注意了。

下面就给出实现了深克隆的代码: (关于仅仅使用浅克隆的结果想必很容易想到,所以就不贴上来了)

不过这里我依旧把简历的类结构图贴上来:

 

 

 

classBirthTime :ICloneable{         private int year;         public int Year         {                   get{ return year; }                   set{ year = value; }         }          private int month;         public int Month         {                   get{ return month; }                   set{ month = value; }         }          private int day;         public int Day         {                   get{ return day; }                   set{ day = value; }         }          public Object Clone()                                                                         //时间类实现Clone方法         {                   return (Object)this.MemberwiseClone();         }}; classRectangle :ICloneable{         private int length;         private int width;         private string color;         private BirthTime bt;         private string author;          public Rectangle(string author)         {                   this.author = author;                   bt = new BirthTime();         }          public Rectangle(BirthTime bt)         {                                                                                                                                 //这个构造函数是为了将来深克隆用的                   this.bt = (BirthTime)bt.Clone();                                             //这里我们虽然是浅克隆,但是我们这里也只需要浅克隆就行了,因为该类里全是值类型而没有引用的         }          //detail infomation         public void SetTangleInfo(int length, intwidth, string color)         {                   this.length = length;                   this.width = width;                   this.color = color;         }          //set create time         public void SetTime(int year, int month,int day)         {                   bt.Year = year;                   bt.Month = month;                   bt.Day = day;         }          //show         public void Display()         {                   Console.WriteLine("{0}{1} {2}", length, width, color);                   Console.WriteLine("CreateTime : {0} {1} {2}, Author : {3} ", bt.Year, bt.Month, bt.Day, author);         }          public Object Clone()         {                   Rectangle obj = new Rectangle(this.bt);                            //这里就用到了之前准备好的构造函数,能这么用也依赖于BirthTime类中没有引用且实现的浅克隆(如果BirthTime中有引用,那么就需要一层一层的浅克隆来实现接下来一层的深克隆了)                   obj.length = this.length;                   obj.width = this.width;                   obj.color = this.color;                   obj.author = this.author;                   return obj;                                                                                            //最终返回一个深复制的矩形对象         }}; //客户端voidmain(){         Rectangle a = new Rectangle("Ben");         a.SetTangleInfo(10, 20, "red");         a.SetTime(2015,4,9);          //只需要调用Clone方法就可以实现新矩形的生成,并且可以修改新矩形的细节         Rectangle b = (Rectangle)a.Clone();         b.SetTime(2015,4,10);          Rectangle c = (Rectangle)a.Clone();         c.SetTangleInfo(20, 10, "blue");          a.Display();         b.Display();         c.Display();}


 

这样,我们的输出结果就不再像浅克隆一样,a和b的时间类指向同一个时间对象,导致输出相同的时间了。

0 0
原创粉丝点击