zoukankan      html  css  js  c++  java
  • 设计模式学习笔记(六)——Prototype原型模式

     

        Prototype原型模式是一种创建型设计模式,它主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变 化,但是他们却拥有比较稳定一致的接口。感觉好像和前几篇所说的设计模式有点分不清,下面我们先来回顾一下以前的几种设计模式,予以区分,再来说说原型模 式。

      Singleton单件模式解决的问题是:实体对象个数问题(这个现在还不太容易混)

           AbstractFactory抽象工厂模式解决的问题是:“一系列互相依赖的对象”的创建工作

           Builder生成器模式解决的问题是:“一些复杂对象”的创建工作,子对象变化较频繁,对算法相对稳定

          FactoryMethor工厂方法模式解决的问题是:某个对象的创建工作

          再回来看看今天的Prototype原型模式,它是用来解决“某些结构复杂的对象”的创建工作。现在看看,好象还是差不多。这个问题先放在这,我们先往下看Prototype原型模式。

          《设计模式》中说道:使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

          此时注意:原型模式是通过拷贝自身来创建新的对象,这一点和其他创建型模式不相同。好,我们再来看看原型模式的结构

    这个结构说明原型模式的客户端程序(ClientApp)是依赖于抽象(Prototype),而对象的具体实现也是依赖于抽象(Prototype)。符合设计模式原则中的依赖倒置原则——抽象不应依赖于具体实现,具体实现应依赖于抽象。

     我们现在回来看看原型模式的实现,我定义了一个场景,一个人开这一辆车在一条公路上。现在这件事是确定的,但不确定的有几点:1、人:姓名,性别,年龄;2车:什么牌子的;3公路:公路名字,长度,类型(柏油还是土路)。现在我们一个个实现。

           先来实现人,定义一个抽象类,AbstractDriver,具体实现男性(Man)和女性(Women)

    public abstract class AbstractDriver {

       public AbstractDriver()

            {

                //

                // TODO: 在此处添加构造函数逻辑

                //

            }

            public string name;

            public string sex;

            public int age;

            public abstract string drive();

            public abstract AbstractDriver Clone();

        }

        public class Man:AbstractDriver

        {

            public Man(string strName,int intAge)

            {

                sex = "Male";

                name = strName;

                age = intAge;

            }

            public override string drive()

            {

                return name + " is drive";

            }

            public override AbstractDriver Clone()

            {

                return (AbstractDriver)this.MemberwiseClone();

            }

        }

        public class Women:AbstractDriver

        {

            public Women(string strName,int intAge)

            {

                sex = "Female";

                name = strName;

                age = intAge;

            }

            public override string drive()

            {

                return name + " is drive";

            }

            public override AbstractDriver Clone()

            {

                return (AbstractDriver)this.MemberwiseClone();

            }

        } 注意:抽象代码中有一个Clone的方法,个人认为这个方法是原型模式的一个基础,因为前面讲了原型模式是通过拷贝自身来创建新的对象。下面我们再来实现公路和汽车---- 》公路:

    public abstract class AbstractRoad

        {

            public AbstractRoad()

            {

                //

                // TODO: 在此处添加构造函数逻辑

                //

            }

            public string Type;

            public string RoadName;

            public int RoadLong;

            public abstract AbstractRoad Clone();//克隆方法,返回值为该类的类名

        }

        public class Bituminous:AbstractRoad    //柏油路

        {

            public Bituminous(string strName,int intLong)

            {

                RoadName = strName;

                RoadLong = intLong;

                Type = "Bituminous";

            }

            public override AbstractRoad Clone()

            {

                return (AbstractRoad)this.MemberwiseClone();//了解MemberwiseClone的含义

            }

        }

        public class Cement:AbstractRoad        //水泥路

        {

            public Cement(string strName,int intLong)

            {

                RoadName = strName;

                RoadLong = intLong;

                Type = "Cement";

            }

            public override AbstractRoad Clone()

            {

                return (AbstractRoad)this.MemberwiseClone();

            }

        }

        -----》汽车:

        public abstract class AbstractCar

        {

            public AbstractCar()

            {

                //

                // TODO: 在此处添加构造函数逻辑

                //

            }

            public string OilBox;

            public string Wheel;

            public string Body;

            public abstract string Run();

            public abstract string Stop();

            public abstract AbstractCar Clone();

        }

        public class BMWCar:AbstractCar

        {

            public BMWCar()

            {

                OilBox = "BMW's OilBox";//注意变量在继承抽象类的子类中的格式

                Wheel = "BMW's Wheel";

                Body = "BMW's body";

            }

            public override string Run()

            {

                return "BMW is running";

            }

            public override string Stop()

            {

                return "BMW is stoped";

            }

            public override AbstractCar Clone()

            {

                return (AbstractCar)this.MemberwiseClone();

            }

        }

        public class BORACar:AbstractCar

        {

            public BORACar()

            {

                OilBox = "BORA's OilBox";

                Wheel = "BORA's Wheel";

                Body = "BORA's Body";

            }

            public override string Run()

            {

                return "BORA is running";

            }

            public override string Stop()

            {

                return "BORA is stoped";

            }

            public override AbstractCar Clone()

            {

                return (AbstractCar)this.MemberwiseClone();

            }

        }

        public class VolvoCar:AbstractCar

        {

            public VolvoCar()

            {

                OilBox = "Volvo's OilBox";

                Wheel = "Volvo's Wheel";

                Body = "Volvo's Body";

            }

            public override string Run()

            {

                return "Volvo is running";

            }

            public override string Stop()

            {

                return "Volvo is stoped";

            }

            public override AbstractCar Clone()

            {

                return (AbstractCar)this.MemberwiseClone();

            }

        }

     然后我们再来看看场景,我们定义一个Manage类,在这个场景中有一个人,一辆车和一条公路,代码实现如下:

    class Manage

        {

            public AbstractCar Car;

            public AbstractDriver Driver;

            public AbstractRoad Road;

            public void Run(AbstractCar car,AbstractDriver driver,AbstractRoad road)

            {

                Car = car.Clone();

                Driver = driver.Clone();

                Road = road.Clone();

            }

        }

        可以看到,在这个代码中,场景只是依赖于那几个抽象的类来实现的。最后我们再来实现一下客户代码,比如我现在要一辆Volvo车,一个叫“Anli”的女司机,在一条叫“Road1”、长1000的柏油路上。

            static void Main(string[] args)

            {

                Manage game = new Manage();

                game.Run(new VolvoCar(),new Women("Anli",18),new Bituminous("Road1",1000));

                Console.Write("CarRun:" + game.Car.Run() + "\n");

                Console.Write("DriverName:" + game.Driver.name + "\n");

                Console.Write("DriverSex:" + game.Driver.sex + "\n");

                Console.Write("RoadName:" + game.Road.RoadName + "\n");

                Console.Write("RoadType:" + game.Road.Type + "\n");

                Console.Write("CarStop:" + game.Car.Stop() + "\n");

                Console.Read();

            }

        运行的结果是:

        CarRun:Volvo is running

    DriverName:Anli

    DriverSex:Female

    RoadName:Road1

    RoadType:Bituminous

    CarStop:Volvo is stoped

    这样,经过简单的更改,可以实现实现细节的变化。

    现在我们再来看看原型模式的几个要点:

    1、Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。

    2、Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来实现,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方不断地Clone。

    3、Prototype模式中的Clone方法可以利用Object类的MemberwiseClone()或者序列化来实现深拷贝。

    这里面我们再来说说浅拷贝和深拷贝。我想对于Prototype模式是很重要的。我觉得浅拷贝和深拷贝的关键区别是对于引用对象的拷贝。例如我们有一个类Class1,

    public class Class1

    {

        int a;

        int[] b;

    }

    我们用浅拷贝实现了两个对象c1和c2,对于c1.a和c2.a,他们所有的内存空间是不一样的,但是c1.b和c2.b,由于它们是引用类型,在浅拷贝时只是拷贝了一个地址给b成员,实际上c1.b和c2.b指向同一块内存。

    但如果我们用深拷贝,c1.b和c2.b指向的是不同的内存地址。那又如何实现深拷贝呢?我们可以利用序列化和反序列化来实现。

    网 友观点一:我觉得prototype的重点在于:只要你传递一个prototype实例到你的run函数中,那么在run函数中就可以创建N个 prototype的新的实例。只要clone方法是深复制。那么你创建的实例就可以完全独立。不会修改了这个实例的值,其他的值也跟着变。这样在run 函数中就不用不断的用new去创建实例。这样做的好处是面对接口编程,也就是依赖倒置。

    网友观点二:介绍到class Manage时,在Run函数中,相当于是保存各个protoType实例,不需要用到clone吧,例子里面使用clone的需求没提到,因为没有新的 实例需要产生,我觉得可以改成:之后某人又开了第二辆同样的车过来……然后添一个AddRun(),这样就必须要用到clone不可了。

  • 相关阅读:
    16-高级指针
    15-C语言结构体
    14-C语言宏
    13-C语言字符串函数库
    12-C语言字符串
    11-C语言指针
    10-C语言函数
    POJ 1001 高精度乘法
    POJ 1060 多项式乘法和除法取余
    POJ 1318 字典排序
  • 原文地址:https://www.cnblogs.com/SunDexu/p/2763533.html
Copyright © 2011-2022 走看看