第548篇--设计模式系统-ProtoType

陌路散爱 提交于 2019-11-26 21:34:00

   Enemy类是抽象原型,它有两个用途,一是定义了原型的一些抽象内容,二是定义了原型模式必须的拷贝方法。在这里,我们看到,每个敌人的属性有位置、攻击力、速度等,并且能通过ShowInfo()方法来获取这个人的信息。

   Clone()方法接受一个参数,表示是否是深拷贝。在这里,我们通过序列化反序列化实现深拷贝,深拷贝实现对象的完整复制,包括对象内部的引用类型都会复制一份全新的。在这里,如果3个敌人对象的Location都指向内存同一个地址的话,那么它们就分不开了,因此,在复制的时候需要进行深拷贝,使得它们的Location是独立的。

注:试一下把MemberwiseClone, 然后改动各自的position,看是不是会改动?

如果改成MemberwiseClone, 则所有的对象引用同一个地址,对一个对象的改动,会影响所有对象。

在初始化Enemy的时候,我们Sleep()了一下,目的是模拟对象的创建是一个非常耗时的工作,这也体现了原型模式的另一个优势,在生成敌人的时候,我们其实无需再做这些工作了,我们只需要得到它的完整数据,并且进行一些修改就是一个新的敌人。

    运行程序后可以看到,虽然创建了三个敌人,但是只耗费了一个敌人的创建时间,三个敌人都是从原型克隆出来的。由于进行了深拷贝,修改了一个敌人的位置并不会影响其它敌人。

运行程序,发现,确是只调用了一次Sleep方法,所以创建N个Enemy,只创建了一次初始化过程.

何时采用

l         从代码角度来说, 如果你希望运行时指定具体类(比如是使用Footman作为敌人还是使用其它),或者你希望避免创建对象时的初始化过程(如果这个过程占用的时间和资源都非常多),或者是希望避免使用工厂方法来实现多态的时候,可以考虑原型模式。

l         从 应用角度来说, 如果你创建的对象是多变化、多等级的产品,或者产品的创建过程非常耗时的时候(比如,有一定的计算量,或者对象创建时需要从网络或数据库中获取一定的数 据),或者想把产品的创建独立出去,不想了解产品创建细节的时候可以考虑使用。不得不说,原型模式给了我们多一种创建对象,并且不依赖具体对象的选择。

注意事项

 l         注意选择深拷贝和浅拷贝。

l         拷贝原型并进行修改意味着原型需要公开更多的数据,对已有系统实现原型模式可能修改的代价比较大。dow copy,原始对象的初始化,只会执行一次。不同点是引用地址是共享,还是独有。

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Threading;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;
namespace PrototypeDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            Enemy enemyPrototype = new FootMan(5, 4, new Location(100, 200));

            GameScene gs = new GameScene();
            List<Enemy> enemyGroup = gs.CreateEnemyGroup(enemyPrototype);

            foreach (FootMan ft in enemyGroup)
            {
                ft.ShowInfo();
                ft.FootmanAttack();
            }

            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }

    /// <summary>
    /// 如果改成MemberwiseClone,  刚是shadow copy, 任何一个的改动,都会影响到其他Clone的属性改动。
    /// 因为所有的Clone的引用是同一个地址.
    /// </summary>
    class GameSceneShadowCopy
    {
        public List<Enemy> CreateEnemyGroup2(Enemy enemyPrototype)
        {
            List<Enemy> enemyGroup = new List<Enemy>();

            Enemy e1 = enemyPrototype.Clone(false );
            e1.Location.x = enemyPrototype.Location.x - 10;

            Enemy e2 = enemyPrototype.Clone(false);
            e2.Location.x = enemyPrototype.Location.x + 10;

            Enemy elite = enemyPrototype.Clone(false);
            elite.Power = enemyPrototype.Power * 2;
            elite.Speed = enemyPrototype.Speed * 2;
            elite.Location.x = enemyPrototype.Location.x;
            elite.Location.y = enemyPrototype.Location.y + 10;

            enemyGroup.Add(e1);
            enemyGroup.Add(e2);
            enemyGroup.Add(elite);

            return enemyGroup;
        }
    }


    /// <summary>
    /// 制造出一系列的Enemy类, 因为是Deep copy, 每一个对象都指向一个不同的指针,所以针对一个对象的改动,不会影响到另一个对象.
    /// </summary>
    class GameScene
    {
        public List<Enemy> CreateEnemyGroup(Enemy enemyPrototype)
        {
            List<Enemy> enemyGroup = new List<Enemy>();

            Enemy e1 = enemyPrototype.Clone(true);
            e1.Location.x = enemyPrototype.Location.x - 10;

            Enemy e2 = enemyPrototype.Clone(true);
            e2.Location.x = enemyPrototype.Location.x + 10;

            Enemy elite = enemyPrototype.Clone(true);
            elite.Power = enemyPrototype.Power * 2;
            elite.Speed = enemyPrototype.Speed * 2;
            elite.Location.x = enemyPrototype.Location.x;
            elite.Location.y = enemyPrototype.Location.y + 10;

            enemyGroup.Add(e1);
            enemyGroup.Add(e2);
            enemyGroup.Add(elite);

            return enemyGroup;
        }
    }

    [Serializable]
    class Location
    {
        public int x;
        public int y;
        public Location(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }

    /// <summary>
    /// Enemy基类
    /// </summary>
    [Serializable]
    abstract class Enemy
    {
        protected Location location;
        public Location Location
        {
            get { return location; }
            set { location = value; }
        }
        protected int power;
        public int Power
        {
            get { return power; }
            set { power = value; }
        }
        protected int speed;
        public int Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        public abstract Enemy Clone(bool isDeepCopy);
        public abstract void ShowInfo();

        /// <summary>
        /// This simulates the time consuming task.
        /// </summary>
        /// <param name="power"></param>
        /// <param name="speed"></param>
        /// <param name="location"></param>
        public Enemy(int power, int speed, Location location)
        {
            Thread.Sleep(1000); // Construct method is assumed to be a high calc work.
            this.power = power;
            this.speed = speed;
            this.location = location;
        }
    }

    /// <summary>
    ///敌人子类
    /// </summary>
    [Serializable]
    class FootMan : Enemy
    {
        private string model;
        public FootMan(int power, int speed, Location location)
            : base(power, speed, location)
        {
            model = "footman";
        }
        public override void ShowInfo()
        {
            Console.WriteLine("model:{0} power:{1} speed:{2} location:({3},{4})", model, power, speed, location.x, location.y);
        }

        /// <summary>
        /// 创建FootMan原型Clone
        /// </summary>
        /// <param name="isDeepCopy"></param>
        /// <returns></returns>
        public override Enemy Clone(bool isDeepCopy)
        {
            FootMan footman;
            if (isDeepCopy)
            {
                MemoryStream memoryStream = new MemoryStream();
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(memoryStream, this);
                memoryStream.Position = 0;
                footman = (FootMan)formatter.Deserialize(memoryStream);
            }
            else
                footman = (FootMan)this.MemberwiseClone();
            return footman;
        }

        public void FootmanAttack()
        {
            Console.WriteLine("FootmanAttack");
        }
    }
}

UML类图:

UML源图:https://skydrive.live.com/#cid=6B286CBEF1610557&id=6B286CBEF1610557!726

源码下载: https://skydrive.live.com/#cid=6B286CBEF1610557&id=6B286CBEF1610557!726

转载于:https://www.cnblogs.com/shanghaijimzhou/archive/2013/05/05/3061762.html

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!