稻草堆上打着滚儿

稻草堆上打着滚儿

讲故事

最近重温了一下星爷的《唐伯虎点秋香》,依然让我捧腹不已,幻想着要是我也能有一名秋香如此的侍女,夫复何求呀,带着这个美好的幻想沉沉睡去...

突然想到,我是一名程序猿呀,想要什么对象不是易如反掌吗,New一个呗,不光是秋香,春、夏、冬都要,身材要超A的,百度好三围(82, 54, 86),开干...

Coding

客户端生产美女

    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}");
        }
    }

结果展示:

生产第一名美女耗时:3008/ms

生产第二名美女耗时:3001/ms

生产第三名美女耗时:3000/ms

我是 秋香,身材[82-54-86],我的才艺是 弹琴
我是 春香,身材[82-54-86],我的才艺是 画画
我是 夏香,身材[82-54-86],我的才艺是 舞蹈

我的美人产生了,但就是每次都是通过New创建,设置的标准身材(82-54-86)不变但每次都要设置,而且每次耗时都很长,要是再生产更多,岂不劳累又耗时...

正在苦恼之时,突然灵感乍现,可以使用原型模式(Prototype)解决呀

Code Upgrade

开始改造:

客户端生产时,除第一个调用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出来的对象基本不耗时,而且不用重复设置固定属性(三围)(一般在初始化的信息不发生变化的情况下,克隆是最好的方法,既隐藏了对象创建的细节,又对性能大大的提高),我心甚欢...

于是想着对美人的才艺进行升级

客户端设置才艺段位:

    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] ???

良久平息之后,才明白导致上面结果的原因,也将是本文的重点:浅复制与深复制

浅复制与深复制

这就是上面,三个美人的才艺最后都变成一样的原因,才艺Talent是一个引用类型,复制三份的是Talent的引用,都指向同一个Talent对象

解决上面的问题,我们就要用深复制,要对Talent复制一个新对象,而不是一个引用。('美人'引用了'才艺',假如'才艺'里还有 引用,很多层,就涉及到深复制要深入多少层的问题,需要事先考虑好,而且要当心出现循环引用的问题,本次案例我们就深入到第一层就可以了)

上代码:

客户端通以前一样,展示结果:

生产第一名美女耗时: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

04-24 20:53