最近重温了一下星爷的《唐伯虎点秋香》,依然让我捧腹不已,幻想着要是我也能有一名秋香如此的侍女,夫复何求呀,带着这个美好的幻想沉沉睡去...git
忽然想到,我是一名程序猿呀,想要什么对象不是易如反掌吗,New一个呗,不光是秋香,春、夏、冬都要,身材要超A的,百度好三围(82, 54, 86),开干...app
Beauty类,包含美人的属性函数
public class Beauty { public Beauty(int bust, int theWaist, int hipline) { Bust = bust; TheWaist = theWaist; Hipline = hipline; //模拟产生一名美人的时长 Thread.Sleep(3000); } /// <summary> /// 名称 /// </summary> public string Name { get; set; } /// <summary> /// 才艺 /// </summary> public string Talent { get; set; } /// <summary> /// 胸围 /// </summary> public int Bust { get; set; } /// <summary> /// 腰围 /// </summary> public int TheWaist { get; set; } /// <summary> /// 臀围 /// </summary> public int Hipline { get; set; } /// <summary> /// 起名 /// </summary> /// <param name="name"></param> public void SetName(string name) { Name = name; } /// <summary> /// 设置才艺 /// </summary> /// <param name="talent"></param> public void SetTalent(string talent) { Talent = talent; } }
客户端生产美女性能
internal class Program { private static void Main(string[] args) { var sw = new Stopwatch(); sw.Start(); var beauty1 = new Beauty(82, 54, 86); sw.Stop(); Console.WriteLine($"生产第一名美人耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty1.SetName("秋香"); beauty1.SetTalent("弹琴"); sw.Restart(); var beauty2 = new Beauty(82, 54, 86); sw.Stop(); Console.WriteLine($"生产第二名美人耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty2.SetName("春香"); beauty2.SetTalent("画画"); sw.Restart(); var beauty3 = new Beauty(82, 54, 86); sw.Stop(); Console.WriteLine($"生产第三名美人耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty3.SetName("夏香"); beauty3.SetTalent("舞蹈"); Show(beauty1); Show(beauty2); Show(beauty3); Console.WriteLine("\nHappy Ending~"); Console.ReadLine(); } public static void Show(Beauty beauty) { Console.WriteLine($"我是 {beauty.Name},身材[{beauty.Bust}-{beauty.TheWaist}-{beauty.Hipline}],个人才艺是 {beauty.Talent}"); } }
结果展现:this
生产第一名美女耗时:3008/ms 生产第二名美女耗时:3001/ms 生产第三名美女耗时:3000/ms 我是 秋香,身材[82-54-86],个人才艺是 弹琴 我是 春香,身材[82-54-86],个人才艺是 画画 我是 夏香,身材[82-54-86],个人才艺是 舞蹈
个人美人产生了,但就是每次都是经过New建立,设置的标准身材(82-54-86)不变但每次都要设置,并且每次耗时都很长,要是再生产更多,岂不劳累又耗时...pwa
正在苦恼之时,忽然灵感乍现,可使用原型模式(Prototype)解决呀code
原型模式 用原型实例指定建立对象的种类,而且经过拷贝这些原型建立新的对象对象
其实就是从一个对象再建立另外一个可定制的对象,并且不须要知道任何建立的细节接口
.NET在System命名空间中提供了ICloneable接口,其中只有一个方法Clone(),实现这个接口就能够完成原型模式了。ip
开始改造:
Beauty实现ICloneable接口
public class Beauty : ICloneable { public Beauty(int bust, int theWaist, int hipline) { Bust = bust; TheWaist = theWaist; Hipline = hipline; //模拟产生一名美人的时长 Thread.Sleep(3000); } /// <summary> /// 名称 /// </summary> public string Name { get; set; } /// <summary> /// 才艺 /// </summary> public string Talent { get; set; } /// <summary> /// 胸围 /// </summary> public int Bust { get; set; } /// <summary> /// 腰围 /// </summary> public int TheWaist { get; set; } /// <summary> /// 臀围 /// </summary> public int Hipline { get; set; } /// <summary> /// 起名 /// </summary> /// <param name="name"></param> public void SetName(string name) { Name = name; } /// <summary> /// 设置才艺 /// </summary> /// <param name="talent"></param> public void SetTalent(string talent) { Talent = talent; } public object Clone() { return this.MemberwiseClone(); } }
客户端生产时,除第一个调用new()外,其余使用Clone()方法建立
internal class Program { private static void Main(string[] args) { var sw = new Stopwatch(); sw.Start(); var beauty1 = new Beauty(82, 54, 86); sw.Stop(); Console.WriteLine($"生产第一名美女耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty1.SetName("秋香"); beauty1.SetTalent("弹琴"); sw.Restart(); var beauty2 = (Beauty)beauty1.Clone(); sw.Stop(); Console.WriteLine($"生产第二名美女耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty2.SetName("春香"); beauty2.SetTalent("画画"); sw.Restart(); var beauty3 = (Beauty)beauty1.Clone(); sw.Stop(); Console.WriteLine($"生产第三名美女耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty3.SetName("夏香"); beauty3.SetTalent("舞蹈"); Show(beauty1); Show(beauty2); Show(beauty3); Console.WriteLine("\nHappy Ending~"); Console.ReadLine(); } public static void Show(Beauty beauty) { Console.WriteLine($"我是 {beauty.Name},身材[{beauty.Bust}-{beauty.TheWaist}-{beauty.Hipline}],个人才艺是 {beauty.Talent}"); } }
结果展现:
生产第一名美女耗时:3009/ms 生产第二名美女耗时:0/ms 生产第三名美女耗时:0/ms 我是 秋香,身材[82-54-86],个人才艺是 弹琴 我是 春香,身材[82-54-86],个人才艺是 画画 我是 夏香,身材[82-54-86],个人才艺是 舞蹈
咱们能够看到,除了第一个建立耗时之外,其余Clone出来的对象基本不耗时,并且不用重复设置固定属性(三围)(通常在初始化的信息不发生变化的状况下,克隆是最好的方法,既隐藏了对象建立的细节,又对性能大大的提升),我心甚欢...
因而想着对美人的才艺进行升级
Talent类,对才艺描述,增长才艺段位
public class Talent { /// <summary> /// 才艺名 /// </summary> public string Name { get; set; } /// <summary> /// 段位 /// </summary> public int Level { get; set; }
Beauty类改造
public class Beauty : ICloneable { public Beauty(int bust, int theWaist, int hipline) { Bust = bust; TheWaist = theWaist; Hipline = hipline; Talent = new Talent(); //模拟产生一名美人的时长 Thread.Sleep(3000); } /// <summary> /// 名称 /// </summary> public string Name { get; set; } /// <summary> /// 才艺 /// </summary> public Talent Talent { get; set; } /// <summary> /// 胸围 /// </summary> public int Bust { get; set; } /// <summary> /// 腰围 /// </summary> public int TheWaist { get; set; } /// <summary> /// 臀围 /// </summary> public int Hipline { get; set; } /// <summary> /// 起名 /// </summary> /// <param name="name"></param> public void SetName(string name) { Name = name; } /// <summary> /// 设置才艺 /// </summary> /// <param name="talent"></param> public void SetTalent(string name, int level) { Talent.Name = name; Talent.Level = level; } public object Clone() { return this.MemberwiseClone(); } }
客户端设置才艺段位:
internal class Program { private static void Main(string[] args) { var sw = new Stopwatch(); sw.Start(); var beauty1 = new Beauty(82, 54, 86); sw.Stop(); Console.WriteLine($"生产第一名美女耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty1.SetName("秋香"); beauty1.SetTalent("弹琴", 10); sw.Restart(); var beauty2 = (Beauty)beauty1.Clone(); sw.Stop(); Console.WriteLine($"生产第二名美女耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty2.SetName("春香"); beauty2.SetTalent("画画", 9); sw.Restart(); var beauty3 = (Beauty)beauty1.Clone(); sw.Stop(); Console.WriteLine($"生产第三名美女耗时:{sw.ElapsedMilliseconds}/ms\n"); beauty3.SetName("夏香"); beauty3.SetTalent("舞蹈", 8); Show(beauty1); Show(beauty2); Show(beauty3); Console.WriteLine("\nHappy Ending~"); Console.ReadLine(); } public static void Show(Beauty beauty) { Console.WriteLine($"我是 {beauty.Name},身材[{beauty.Bust}-{beauty.TheWaist}-{beauty.Hipline}],个人才艺是 {beauty.Talent.Name} 段位 {beauty.Talent.Level}"); } }
结果展现:
生产第一名美女耗时:3022/ms 生产第二名美女耗时:0/ms 生产第三名美女耗时:0/ms 我是 秋香,身材[82-54-86],个人才艺是 舞蹈 段位 8 我是 春香,身材[82-54-86],个人才艺是 舞蹈 段位 8 我是 夏香,身材[82-54-86],个人才艺是 舞蹈 段位 8
看到结果我懵了,什么状况,我明明把才艺设置的不同,怎么三个最后都是 [舞蹈 段位 8] ???
良久平息以后,才明白致使上面结果的缘由,也将是本文的重点:浅复制与深复制
浅复制:复制获得的对象的全部变量都包含有与原来的对象相同的值,而全部的对其余对象的引用都仍然指向原来的对象。
MemberwiseClone()方法就是浅复制,若是字段是值类型的,则对该字段执行逐位复制,若是字段是引用类型,则复制引用但不复制引用对象,所以原始对象及其复本引用同一对象。
这就是上面,三个美人的才艺最后都变成同样的缘由,才艺Talent是一个引用类型,复制三份的是Talent的引用,都指向同一个Talent对象
深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
解决上面的问题,咱们就要用深复制,要对Talent复制一个新对象,而不是一个引用。('美人'引用了'才艺',假如'才艺'里还有 引用,不少层,就涉及到深复制要深刻多少层的问题,须要事先考虑好,并且要小心出现循环引用的问题,本次案例咱们就深刻到第一层就能够了)
上代码:
Talent类,实现ICloneable接口
public class Talent : ICloneable { /// <summary> /// 才艺名 /// </summary> public string Name { get; set; } /// <summary> /// 段位 /// </summary> public int Level { get; set; } public object Clone() { return this.MemberwiseClone(); } }
Beauty类,增长私有构造函数,以便克隆“才艺”的克隆数据
public class Beauty : ICloneable { public Beauty(int bust, int theWaist, int hipline) { Bust = bust; TheWaist = theWaist; Hipline = hipline; Talent = new Talent(); //模拟产生一名美人的时长 Thread.Sleep(3000); } private Beauty(Talent talent) { this.Talent = (Talent)talent.Clone(); } /// <summary> /// 名称 /// </summary> public string Name { get; set; } /// <summary> /// 才艺 /// </summary> public Talent Talent { get; set; } /// <summary> /// 胸围 /// </summary> public int Bust { get; set; } /// <summary> /// 腰围 /// </summary> public int TheWaist { get; set; } /// <summary> /// 臀围 /// </summary> public int Hipline { get; set; } /// <summary> /// 起名 /// </summary> /// <param name="name"></param> public void SetName(string name) { Name = name; } /// <summary> /// 设置才艺 /// </summary> /// <param name="talent"></param> public void SetTalent(string name, int level) { Talent.Name = name; Talent.Level = level; } public object Clone() { //调用私有构造方法,让“才艺”克隆完成,而后再给这个 “美人” 对象的相关字段赋值, //最终返回一个深复制的 “美人” 对象 var beauty = new Beauty(Talent) { Bust = this.Bust, TheWaist = this.TheWaist, Hipline = this.Hipline }; return beauty; } }
客户端通之前同样,展现结果:
生产第一名美女耗时:3008/ms 生产第二名美女耗时:0/ms 生产第三名美女耗时:0/ms 我是 秋香,身材[82-54-86],个人才艺是 弹琴 段位 10 我是 春香,身材[82-54-86],个人才艺是 画画 段位 9 我是 夏香,身材[82-54-86],个人才艺是 舞蹈 段位 8
看到结果,我心甚喜。忽然屋内彩虹环绕,三位美人出如今我面前,婀娜妖娆,不对,怎么少了个人冬香,爬向键盘...
叮铃铃,叮铃铃...闹铃响了
握艹,我要续梦~
源码地址: https://gitee.com/sayook/DesignMode/tree/master/Prototype