快跑啊兔兔 阅读(79) 评论(0)

一、引言

相信大家都看过西游记中孙悟空拔一根汗毛吹出千万只猴子,可有没有想过如果这些猴子一只一只的去经历和孙悟空一样的成长过程才能产生,这是何其的复杂和耗费精力啊?!类比在程序设计中,当需要创建多个相同的类的实例,这个创建过程又是极其复杂时,使用new操作符一个个去创建会增加内存开销和程序复杂度。显然,采用工厂方法模式是不适合的,没必要每次都new一个相同的类的实例对象。建造者模式就更不用说了,是相同构建步骤创建不同的表示,一步步的创建也太麻烦了。那现在解决思路是 创建一个类的实例对象,如果后来再创建这样的实例,可以通过对原来对象拷贝一份完成创建,这样内存中就不要再重复创建相同的实例,减少内存开销,达到类实例复用的效果。这其实就是今天我们要学习的原型模式

二、原型模式

在现实生活中也我们用复印机复印出多份相同的简历,电视中孙悟空吹出千万只猴子等,都体现了原型模式思想,下面通过孙悟空的例子帮助我们理解原型模式

    //孙悟空打怪经历类
    class WorkExperience:ICloneable
    {
        //时间段
        public string TimeArea{get;set;}
        //妖魔鬼怪
        public string Demon{get;set;}

        public object Clone()
        {
           return (object)this.MemberwiseClone();
        }
    }

 

 //浅复制 
     class ShallowMonkeyPrototype:ICloneable
    {
         private string Name;
         private string Age;
         private string Sex;

         private WorkExperience work;

         public ShallowMonkeyPrototype(string name)
         {
             this.Name = name;
             work = new WorkExperience();
         }
         //可以设置孙悟空的个人简介
         public void SetMonkeyPrototype(string age,string sex)
         {
             this.Age = age;
             this.Sex = sex;
         }
         //可以设置孙悟空的打怪经历
         public void SetWorkExperience(string timearea,string demon)
         {
             work.TimeArea = timearea;
             work.Demon = demon;
         }
         //显示
         public void Display()
         {
             Console.WriteLine("{0},{1},{2}",this.Name,this.Age,this.Sex);
             Console.WriteLine("打怪经历:{0},{1}",work.TimeArea,work.Demon);
         }
         //MemberwiseClone方法(MSDN上的解释) 创建一个新的对象,然后复制当前对象的非静态字段的新对象创建一个浅表副本.
         //如果字段是值类型,则会执行字段的逐位副本。如果字段是引用类型,则引用对象被复制,但引用对象不是;因此原始对象及克隆引用了相同的对象
        public object Clone()
        {
            return (object)this.MemberwiseClone();
        }
    }

 

  //深复制
     class DeepMonkeyPrototype:ICloneable
    {
         private string Name;
         private string Age;
         private string Sex;

         private WorkExperience work;

         public DeepMonkeyPrototype(string name)
         {
             this.Name = name;
             work = new WorkExperience();
         }

         private DeepMonkeyPrototype(WorkExperience work)
         {
            this.work=(WorkExperience)work.Clone();
         }

         public void SetMonkeyPrototype(string age,string sex)
         {
             this.Age = age;
             this.Sex = sex;
         }

         public void SetWorkExperience(string timearea,string demon)
         {
             work.TimeArea = timearea;
             work.Demon = demon;
         }

         public void Display()
         {
             Console.WriteLine("{0},{1},{2}",this.Name,this.Age,this.Sex);
             Console.WriteLine("打怪经历:{0},{1}",work.TimeArea,work.Demon);
         }

        public object Clone()
        {
            DeepMonkeyPrototype monkey = new DeepMonkeyPrototype(this.work);
            monkey.Name = this.Name;
            monkey.Age = this.Age;
            monkey.Sex = this.Sex;
            return monkey;
        }
    }

 

  class Program
    {
        static void Main(string[] args)
        {
            #region  //浅复制 客户端调用
            ShallowMonkeyPrototype monkey1 = new ShallowMonkeyPrototype("孙悟空");
            monkey1.SetMonkeyPrototype("18", "");
            monkey1.SetWorkExperience("888-889", "白骨精");

            ShallowMonkeyPrototype monkey2 = (ShallowMonkeyPrototype)monkey1.Clone();
            monkey2.SetMonkeyPrototype("19", "");
            monkey2.SetWorkExperience("945-946", "黑熊怪");

            ShallowMonkeyPrototype monkey3 = (ShallowMonkeyPrototype)monkey1.Clone();
            monkey3.SetWorkExperience("1115-1116", "女儿国");
            #endregion
            #region  //深复制 客户端调用
            //DeepMonkeyPrototype monkey1 = new DeepMonkeyPrototype("孙悟空");
            //monkey1.SetMonkeyPrototype("18", "男");
            //monkey1.SetWorkExperience("888-889","白骨精");

            //DeepMonkeyPrototype monkey2 = (DeepMonkeyPrototype)monkey1.Clone();
            //monkey2.SetWorkExperience("945-946", "黑熊怪");

            //DeepMonkeyPrototype monkey3 = (DeepMonkeyPrototype)monkey1.Clone();
            //monkey3.SetWorkExperience("1115-1116", "女儿国");
            #endregion
            monkey1.Display();
            monkey2.Display();
            monkey3.Display();
            Console.Read();
        }
    }

浅复制运行结果

深复制运行结果

通过上面demo的显示,我们可以总结出

优点:原型模式隐藏了创建对象的复杂性,从一个对象再创建另一个可定制的对象,而不需要知道任何创建的细节

那浅复制和深复制又是怎么回事,有什么区别吗?

1.通过两次运行结果的对比,可以看出虽然浅复制时设置了孙悟空不同的打怪经历,但是运行出来他们的经历确实相同的,这是为什么呢??通过分析得知

2.浅复制 被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用都仍然指向原来的对象

3.深复制 把引用的对象的变量指向复制过的新对象,而不是原来被引用的对象

 

原型模式的缺点

1.每个类都必须有个克隆方法

2.配备克隆方法需要对类的功能通盘考虑,当一个类不支持串行化的间接对象,或者引用有循环结构的时候(啊啊啊。。。这一点其实我也不是很理解,先记一下在这里,嘿嘿)

 

本文关于原型模式的学习就到这里结束了,设计模式之创建型设计模式(关注对象的创建)通过前六篇设计模式文章的学习也告一段落,这种先定义,再附demo注释,最后总结这种学习模式怎么样呢,欢迎指出您的看法和改进的地方。

文中如有不足,欢迎斧正,感谢您的阅读。