65.9K
CodeProject 正在变化。 阅读更多。
Home

原型设计模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (13投票s)

2009年9月23日

CPOL

4分钟阅读

viewsIcon

94534

downloadIcon

685

本文通过一个案例研究,展示了我们如何将原型模式用于 Elizabeth 的趣味活动。

背景

在我上一篇文章中,我通过一个伊丽莎白有趣活动的例子介绍了建造者模式。

当伊丽莎白想制作动物时,她需要为每只动物制作头部、身体、腿、手臂和尾巴。她先用模具工具集制作好动物的所有身体部分,然后将它们组装起来制作成一只动物。

在她的有趣活动中,伊丽莎白使用了建造者模式来制作动物。例如,当她想制作一只猴子时,一旦所有五个部分都完成,她就会将它们粘合在一起,然后进行装饰。 

第二天,如果她想再次制作相同的动物,她需要一遍又一遍地重复相同的步骤。最后她厌倦了这样做,所以她问我是否有一个复印机可以帮助她随时复制她想要的动物。嗯,看来伊丽莎白也想遵循“不要重复自己”的编程规则。 

所以,看起来原型设计模式可以满足伊丽莎白的愿望。在这种情况下,伊丽莎白可以复制她的第一只动物(原型动物)并以不同的方式进行装饰。她还可以使用她复制的动物作为原型来制作其他动物。 

引言

原型设计模式也是我们用于获取特定类对象实例的一种模式,例如建造者和工厂模式。我们不必每次都创建一个全新的对象,而是可以立即复制一个已有的对象(可以用作原型的对象)并开始使用它。这样,我们就无需重复创建我们想要使用的对象的构建过程。新的复制对象与原始原型对象完全独立,可以用于任何不会影响原版的目的。复制现有对象没有限制,任何现有对象都可以被复制。本文介绍了我们如何使用原型设计模式来为伊丽莎白的动物实现。 

原型设计模式结构

Prototype.JPG

类图

PrototypeClass.JPG

实现代码

原型对象

动物

Animal 类是我们想要使其可克隆的类。在 C# .NET 中,我们继承 ICloneable 接口来使我们的类成为可克隆类。为了实现 clone() 方法,可以使用浅拷贝或深拷贝。根据我们的需求,我们也可以选择不同的策略来实现浅拷贝或深拷贝。但是,如果我们进行浅拷贝,类中的所有引用变量仍将指向原始原型对象所在的相同地址。Animal 类包含一个接受另一个 Animal 作为参数的构造函数,我在这里编写了所有的克隆过程,这样它就可以在自己的 clone()方法中被调用,以实现自我克隆的能力。另一种使 Animal 可克隆的方法是使用 Serialize 属性使 Animal 类可序列化。我们可以将当前对象序列化到 MemoryStream ,然后将其反序列化为一个新对象作为复制的对象。请通过 MSDN 网站了解更多关于如何进行浅拷贝和深拷贝的详细信息。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Animal : ICloneable
        {
            public Head AHead { get; set; }
            public List<leg> Legs { get; set; }
            public Tail ATail { get; set; }
            public string Name { get; set; }

            public Animal()
            {
                AHead = new Head();
                Legs = new List<leg>();
                ATail = new Tail();
            }

            //Constructor to implement the deep copy here
            public Animal(Animal aAnimal)
            {
                Name = aAnimal.Name;
                AHead = (Head)aAnimal.AHead.Clone();

                Legs = new List<leg>();
                foreach (Leg aLeg in aAnimal.Legs)
                {
                    Legs.Add((Leg)aLeg.Clone());
                }
                ATail = (Tail)aAnimal.ATail.Clone();
            }

            //Helper method to show the result from client
            public void Dispaly()
            {

                Console.WriteLine("I am a " + Name);
                AHead.Display();
                foreach (Leg aleg in Legs)
                {
                    aleg.Display();
                }
                ATail.Display();
                Console.WriteLine();
            }

            #region ICloneable Members
            //call deep coy to perform clone process
            public object Clone()
            {
                return new Animal(this);
            }

            #endregion
        }
    }
}

Head

Head 类是我们将在 Animal 类中声明的另一个类。由于它是我们 Animal 类中的一个引用对象,我也实现了 Clone() 方法,以便在我们需要克隆它时使其自身可克隆。与 Animal 类的区别在于,我在 Clone()方法中使用了 MemberwiseClone()来复制它。 .NET 的 MemberwiseClone() 帮助我们对对象进行浅拷贝。由于我的 head 类中只有 Number int 类型)和 Name string 是引用,但它也是一个不可变的类型,不能被更改。所以,无论是对它进行浅拷贝还是深拷贝都没有区别),MemberwiseClone()应该能很好地处理它。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Head : ICloneable
        {
            public int Number { get; set; }
            public string Name { get; set; }


            public void Display()
            {
                Console.WriteLine("I have {0} {1} ", Number, Name);
            }

            #region ICloneable Members
            //create a shallow copy of current object 
            public object Clone()
            {
                return this.MemberwiseClone();
            }

            #endregion
        }
    }
}

Head相同,Leg 类也继承 ICloneable 以使其自身可被复制。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Leg : ICloneable
        {
            public string Side { get; set; }
            public string Name { get; set; }

            public void Display()
            {
                Console.WriteLine("This is my {0} {1} ", Side, Name);
            }

            #region ICloneable Members

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

            #endregion
        }
    }
}

尾巴

Tail 类是另一个可克隆类,与 Head相同。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Tail : ICloneable
        {
            public string Color { get; set; }

            public void Display()
            {
                Console.WriteLine("My tail is {0}", Color);
            }

            #region ICloneable Members

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

            #endregion
        }
    }
}

客户端应用程序

从客户端来看,伊丽莎白将创建第一个动物对象。之后,她将简单地复制她的第一个动物来玩。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using www.askbargains.com.PrototypeDesignPattern;

namespace www.askbargains.com
{
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                //Elizabeth starts building her first animal
                Animal firstAnimal = new Animal();

                firstAnimal.Name = "Deer";
                //work on head
                firstAnimal.AHead.Name = "Antlers";
                firstAnimal.AHead.Number = 2;

                Leg leftLeg = new Leg();
                leftLeg.Side = "Left";
                leftLeg.Name = "Hoove";

                Leg rightLeg = new Leg();
                rightLeg.Side = "Right";
                rightLeg.Name = "Hoove";

                firstAnimal.Legs.Add(leftLeg);
                firstAnimal.Legs.Add(rightLeg);

                firstAnimal.ATail.Color = "Brown";
                
                //Elizabeth copied the firstAnimal(prototype)
                Animal copiedAnimal =(Animal)firstAnimal.Clone();

                Console.WriteLine("Display the first animal");
                firstAnimal.Dispaly();        
                
                Console.WriteLine("Display the copied animal");
                copiedAnimal.Dispaly();

                //Elizabeth play aroud with the copiedAnimal
                copiedAnimal.Name = "Copied Deer";
                copiedAnimal.AHead.Name = "Antlers";
                copiedAnimal.AHead.Number = 1;
             
                //display the result
                Console.WriteLine("Display the copied animal after some play. 
				Elizabeh only made 1 antler for it");
                copiedAnimal.Dispaly();

                Console.WriteLine("Display the original prototype");
                firstAnimal.Dispaly();
                
                //Elizabeth make an other copy by using the copiedAnimal as the prototype
                Animal secondCopy = (Animal)copiedAnimal.Clone();
                secondCopy.Name = "An other copy";
                
                //Display the second copy
                Console.WriteLine("Display the secnod copy animal");
                secondCopy.Dispaly();
                Console.Read();
            }
        }
    }
}

一旦我们启动客户端应用程序,您将看到复制的对象与原型对象(firstAnimal)完全相同。玩复制的对象不会影响原始原型。很酷。 

Prototype_output.JPG

结论

在本文中,我演示了如何使用原型模式来帮助我们复制现有对象。我还为建造者设计模式编写了另一篇文章,介绍了如何创建对象实例。 

历史

  • 2009 年 9 月 23 日:首次发布
© . All rights reserved.