• Prototype原型模式(创建型模式)


    1、原型模式解决的问题

    现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路.

    前提:抽象变化较慢,实现变化较快(不稳定)

    整个抽象的游戏设施建造系统相对变化较慢,本例中只有一个Build的创建方法,而Build内部的方法实现,该实现依赖与各种具体的实现,而这些实现变化的非常频繁,现在虽然只有现代风格和古典风格的房屋和道路的构建,而将来可能会卡通风格、另类风格等各种各样的对象加入到Build方法中来渲染游戏的背景.

    在不考虑第三方容器组件(如Unity)和设计模式的情况下,为了快速完成这个任务,我们通常会用以下这种方式编码,代码如下:

        #region 抽象A
        /// <summary>
        /// 抽象的游戏设施建造系统
        /// </summary>
        public class BuildSystem
        {
            /// <summary>
            /// Build方法的逻辑变化较慢(只需要创建2种风格的房屋和道路,总共8个对象),但是风格变化较快,由于需求变化,可能需要创建诸如卡通风格、另类风格等的房屋和道路
            /// </summary>
            public void Builld()
            {
                ModernHouse modernHouseA = new ModernHouse();
                ModernHouse modernHouseB = new ModernHouse();
                ModernRoad modernRoadA = new ModernRoad();
                ModernRoad modernRoadB = new ModernRoad();
                ClassicalHouse classicalBuildA = new ClassicalHouse();
                ClassicalHouse classicalBuildB = new ClassicalHouse();
                ClassicalRoad classicalRoadA = new ClassicalRoad();
                ClassicalRoad classicalRoadB = new ClassicalRoad();
                //下面是具体的对象实例操作,如现代化房屋虽然有两个实例,但是可能两个可能高矮、外形不同等
            }
        } 
        #endregion
    
        #region 实现细节b
        /// <summary>
        /// 现代风格的房屋
        /// </summary>
        public class ModernHouse { }
    
        /// <summary>
        /// 现代风格的道路
        /// </summary>
        public class ModernRoad { }
    
        /// <summary>
        /// 古典风格的房屋
        /// </summary>
        public class ClassicalHouse { }
    
        /// <summary>
        /// 古典风格的道路
        /// </summary>
        public class ClassicalRoad { } 
        #endregion

    从oop的角度分析上面的代码,可以理解为抽象的游戏系统直接依赖具体的实现细节(现代风格和古典风格的房屋和道路),如下图:

    这时客户端的调用代码如下:

        /// <summary>
        /// Prototype原型模式-创建型模式
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                BuildSystem buildSystem = new BuildSystem();
                buildSystem.Builld();
            }
        }

    这种设计方式的弊端显而易见,Build方法显得很无力,这个时候增加了一个新的需求,如下:

    客户端需要构建一种卡通风格和另类风格的道路和房屋,但是Build方法的主逻辑还是不变,同样是(创建两种风格的房屋和道路,共8个对象).

    这时Build方法显得很无力,只能创建一种特定逻辑的游戏背景建筑.(当然你可以在BuildSystem中新添一种新的Build方法来满足需求,但是这种方式的代码的重用性差)而且,掉到了,抽象依赖于实现的坑里面去了,这个时候我们就需要对代码进行重构,进行依赖倒置.如下图:

    对所有的Build方法中的8个实例(实现细节b)进行抽象,让它们依赖于抽象B,让Build方法(抽象A)也依赖于抽象B,代码如下:

        #region 抽象A
        /// <summary>
        /// 抽象的游戏设施建造系统
        /// </summary>
        public class BuildSystem
        {
            /// <summary>
            /// Build方法的逻辑变化较慢(只需要创建2种风格的房屋和道路,总共8个对象),但是风格变化较快,由于需求变化,可能需要创建诸如卡通风格、另类风格等的房屋和道路
            /// </summary>
            public void Builld(House houseone, House houseTwo,Road roadone, Road roadtwo)
            {
                House modernHouseA = houseone.Clone();
                House modernHouseB = houseone.Clone();
                Road modernRoadA = roadone.Clone();
                Road modernRoadB = roadone.Clone();
                House classicalBuildA = houseTwo.Clone();
                House classicalBuildB = houseTwo.Clone();
                Road classicalRoadA = roadtwo.Clone();
                Road classicalRoadB = roadtwo.Clone();
                //下面是具体的对象实例操作,如现代化房屋虽然有两个实例,但是可能两个可能高矮、外形不同等
            }
        }
        #endregion
    
        #region 抽象B
        /// <summary>
        /// 抽象房屋
        /// </summary>
        public abstract class House
        {
            /// <summary>
            /// 抽象的House的Clone方法,用于构建House的多个实例,如果抽象A只需要一个实现b的一个实例,则不需要该方法
            /// </summary>
            /// <returns></returns>
            public abstract House Clone();
        }
    
        /// <summary>
        /// 抽象道路
        /// </summary>
        public abstract class Road
        {
            /// <summary>
            ///  抽象的Road的Clone方法,用于构建Road的多个实例,如果抽象A只需要一个实现b的一个实例,则不需要该方法
            /// </summary>
            /// <returns></returns>
            public abstract Road Clone();
        }
        #endregion
    
        #region 实现细节b
        /// <summary>
        /// 现代风格的房屋
        /// </summary>
        public class ModernHouse : House
        {
            public override House Clone()
            {
                //实现ModernHouse的浅拷贝,如果当前对象中含有数组等,则需要使用序列化的方式(深拷贝)实现对象的克隆,否则当一个对象实例修改了数组,另一个对象实例会共享该数组
                return (ModernHouse)MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 现代风格的道路
        /// </summary>
        public class ModernRoad : Road
        {
            public override Road Clone()
            {
                return (ModernRoad)MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 古典风格的房屋
        /// </summary>
        public class ClassicalHouse : House
        {
            public override House Clone()
            {
                return (House)MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 古典风格的道路
        /// </summary>
        public class ClassicalRoad: Road
        {
            public override Road Clone()
            {
                return (ClassicalRoad)MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 卡通风格的房屋
        /// </summary>
        public class CartoonHouse : House
        {
            public override House Clone()
            {
                return (CartoonHouse)MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 卡通风格的道路
        /// </summary>
        public class CartoonRoad : Road
        {
            public override Road Clone()
            {
                return (CartoonRoad)MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 另类风格的房屋
        /// </summary>
        public class AlternativeHouse : House
        {
            public override House Clone()
            {
                return (AlternativeHouse)MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 另类风格的道路
        /// </summary>
        public class AlternativeRoad : Road
        {
            public override Road Clone()
            {
                return (AlternativeRoad)MemberwiseClone();
            }
        }
        #endregion

    这时客户端的调用代码如下:

        class Program
        {
            static void Main(string[] args)
            {
                BuildSystem buildSystem = new BuildSystem();
                //构建卡通风格和另类风格的房屋和道路
                buildSystem.Builld(new CartoonHouse(), new AlternativeHouse(), new CartoonRoad(), new AlternativeRoad());
                //构建现代风格和古典风格的房屋和道路
                buildSystem.Builld(new ModernHouse(),new ClassicalHouse(),new ModernRoad(),new ClassicalRoad());
            }
        }

    ok,重构后的代码,在抽象A相对稳定的情况,通过对实现细节b的抽象,让实现细节b和抽象A都依赖于抽象B,完成了依赖倒置,实现了代码new的解耦,这就是原型模式!

    关于原型模式的几个要点:

    1、Prototype模式用于隔离类对象的使用者和具体类型(易变类)的之间的耦合关系,但是这些易变类必须拥有稳定的接口.

    2、Prototype模式对于"如何创建易变类的对象"采用"原型克隆"的方式来做,它使我们能非常灵活动态的创建某些拥有"稳定接口"的新对象.所需的工作仅仅是创建一个新类的对象即原型,然后在需要的地方不断的Clone.

    3、Prototype模式的Clone方法可以利用Object自带的MemberwiseClone方法,注:该方法只能用于比较简单的类,只能实现浅拷贝,如果类中包含数组等引用类型,则需要使用序列化方法来实现类型的深拷贝

  • 相关阅读:
    参加“51testing第70期深圳技术沙龙”感想
    软件测试的实质
    JMeter使用技巧
    一个软件测试员的工作与学习(二)
    JMeter基础之元件的作用域与执行顺序
    测试之美测试员的心思你不懂
    博客搬家的原因与文章被转的看法
    ubuntu下配置java环境
    敏捷软件测试初见
    软件测试人员分工
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/9788981.html
Copyright © 2020-2023  润新知