• 小白学习设计模式——简单工厂、工厂方法、抽象工厂


        其实看设计模式已有一段时间了,主要是看《大话设计模式》还有四人帮的《设计模式》,总觉得理解的不够全面,这应该跟项目经验有关系,所谓的理论和实践并重。但又觉得学习本来就是这样,对一个知识有一定了解,以后运用或磕碰时再刷新对这个知识的认知,学学还是有好处的~

        用个故事来描述吧,以下故事为虚实结合而成......

        小白正在为公司开发一款射击类游戏,负责的是选枪的模块;提交的代码如下

         static void Main(string[] args)  //客户端代码
            {
                Console.WriteLine("请输入要选择的武器:A.步枪 B.机关枪 C.狙击枪");
                string fireType = Console.ReadLine();
                Weapon fireWeapon = null;
                switch (fireType)
                {
                    case "A":
                        fireWeapon = new 步枪();
                        break;
                    case "B":
                        fireWeapon = new 机关枪();
                        break;
                    case "C":
                        fireWeapon = new 狙击枪();
                        break;
                    default:
                        Console.WriteLine("请选择正确的武器");
                        break;
                }
            }
    
            abstract class Weapon
            {
                //...武器抽象类
            }
    
            class 步枪:Weapon
            { 
                //...省略
            }
            class 机关枪:Weapon
            {
                //...省略
            }
            class 狙击枪:Weapon
            {
                //...省略
            }
    View Code

    提交代码后小白正哼着愉悦的曲子准备打卡,突然那熟悉而又鬼魅的声音打断他。

    总监突然出现在后面说道:"小白,去吃饭啦?赶紧去~吃饭回来啊~”。

    小白:"其实我是下...班"。

    总监:"你看你写些什么!还下班,你怎么可以这么写呢?什么都塞到客户端,这样客户端代码多恶心啊!别吃饭了,快使用简单工厂模式改改!"

    "...好,我这就改!",小白说道。

    不一会儿,小白的代码改出来了:

            static void Main(string[] args)
            {
                Console.WriteLine("请输入要选择的武器:A.步枪 B.机关枪 C.狙击枪");
                string fireType = Console.ReadLine();
                Weapon fireWeapon = WeaponFactory.createWeapon(fireType);
            }
    
            abstract class Weapon
            {
                //...武器抽象类
            }
    
            class 步枪:Weapon
            { 
                //...省略
            }
            class 机关枪:Weapon
            {
                //...省略
            }
            class 狙击枪:Weapon
            {
                //...省略
            }
            
            //增加一个工厂类
            public class WeaponFactory
            {
                public static Weapon createWeapon(string fireType)
                {
                    Weapon fireWeapon = null;
                    switch (fireType)
                    {
                        case "A":
                            fireWeapon = new 步枪();
                            break;
                        case "B":
                            fireWeapon = new 机关枪();
                            break;
                        case "C":
                            fireWeapon = new 狙击枪();
                            break;
                        default:
                            Console.WriteLine("请选择正确的武器");
                            break;
                    }
                    return fireWeapon;
                }
            }
    View Code

    总监:"恩,这样客户端整洁了,而且还能把这个功能复用到web等程序中。"

    简单工厂:就是运用基本的继承多态和抽取工厂方法到达代码整洁和方法复用,自己总结的,书上并没有定义。

    总监:"但是我现在要添加一个武器怎么办?"

    小白:"增加一个"Weapon的子类和增加一个case条件咯"

    总监:"那是不是违反了面向对象的开闭原则(不能修改已经写好的类,只能扩展),我一天增加一种新武器,你这个类岂不是要改烂?赶紧用工厂方法改一下"

    小白:"我肚子饿了..."

    不一会儿,小白的代码又改出来了:

            static void Main(string[] args)  //客户端代码
            {
                Console.WriteLine("请输入要选择的武器:A.步枪 B.机关枪 C.狙击枪");
                string fireType = Console.ReadLine();
                Weapon fireWeapon = null;
                switch (fireType)
                {
                    case "A":
                        fireWeapon = new 步枪工厂().CreateWeapon();
                        break;
                    case "B":
                        fireWeapon = new 机关枪工厂().CreateWeapon();
                        break;
                    case "C":
                        fireWeapon = new 狙击枪工厂().CreateWeapon();
                        break;
                    default:
                        Console.WriteLine("请选择正确的武器");
                        break;
                }
            }
    
            abstract class Weapon
            {
                //...武器抽象类
            }
    
            class 步枪:Weapon
            { 
                //...省略
            }
            class 机关枪:Weapon
            {
                //...省略
            }
            class 狙击枪:Weapon
            {
                //...省略
            }
    
            interface  IFactory
            { 
                //...工厂接口
                Weapon CreateWeapon();
            }
    
            class 步枪工厂 : IFactory
            {
                public Weapon CreateWeapon()
                {
                    return new 步枪();
                }
            }
    
            class 机关枪工厂 : IFactory
            {
                public Weapon CreateWeapon()
                {
                    return new 机关枪();
                }
            }
    
            class 狙击枪工厂 : IFactory
            {
                public Weapon CreateWeapon()
                {
                    return new 狙击枪();
                }
            }
    View Code

    小白:"这样子就解决了工厂方法的问题啦,这样只要在有新增的武器我就加个武器类和相应的工厂类就行啦~吃饭咯~"

    有个问题困扰了我很久,什么工厂方法,不觉得代码看起来跟一开始一样吗?只是套了个工厂的壳,还不如直接创建对象,我觉得有这样的想法还是因为项目经验的不足导致的。直到我看到了百度百科中提到java的collection中的iterator运用了工厂方法(这里可以把list看做工厂,list.iterator就是创建对象的工厂方法)。设计模式多数可能是嵌套应用在某一个特定场景,所以当你遇到这些场景之后才能算真正理解设计模式带来的好处。

    ”工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中“这个是设计模式书中的原话,一直都不知道他什么意思,也是看到下面java迭代器的例子才明白(创建出来的是什么迭代器,完全是由集合的子类来决定的,附java代码)

    List list=new ArrayList();
    Iterator iter = list.iterator();
    while(iter.hasNext())
    {
        //do something...
    }

    总监:"嗯...问题是解决了,可是客户端又变恶心了,赶紧去给我处理下,用反射什么的试试...这么晚了外面餐馆也关门了,待会请你吃泡面吧"

    小白:"卧槽都饿扁了吃泡面哪够...."

            private static readonly string AssemblyName = "当前程序集名称";
            private static readonly string factory = ConfigurationManager.AppSettings["factory"];
            static void Main(string[] args)  //客户端代码
            {
                IFactory weaponFactory = (IFactory)Assembly.Load("当前程序集名称").CreateInstance("当前程序集名称" + "." + factory);
    Weapon.fireWeapon= weaponFactory.CreateWeapon(); }
    //....下面的代码与上面一样,省略

    小白:"这样只要在配置文件中更改要创建的武器名字就可以啦~"

    总监:"恩...好吧,今天就到这里,给你泡面,下班吧。"

    小白:"ye!!泡面泡起来!"

    客户:"等下,小白同学,我这里怎么报错了奇怪了,你过来看看"

    小白:"卧槽客户你哪冒出来的,这么晚了还在这里!"

    小白:"......卧槽你搞什么,步枪的子弹怎么能跟火箭筒一起用!?"

    客户:"不小心按到.....不对,都怪你,怎么可以让我按错呢,你程序不应该有什么容错性的吗?赶紧给我改!"

    总监:"还不快去改!用抽象工厂试试!"

    小白:"我..要..睡觉TT"

            private static readonly string AssemblyName = "当前程序集名称";
            private static readonly string factory = ConfigurationManager.AppSettings["factory"];
            static void Main(string[] args)  //客户端代码
            {
                IFactory weaponFactory = (IFactory)Assembly.Load("当前程序集名称").CreateInstance("当前程序集名称" + "." + factory);
                Weapon fireWeapon = weaponFactory.CreateWeapon();
                Bullet fireBullet =weaponFactory.CreateBullet();
            }
    
            abstract class Weapon
            {
                //...武器抽象类
            }
    
            class 步枪:Weapon
            { 
                //...省略
            }
            class 机关枪:Weapon
            {
                //...省略
            }
            class 狙击枪:Weapon
            {
                //...省略
            }
            abstract class Bullet
            {
                //...子弹抽象类
            }
            class 步枪子弹 : Bullet
            { 
                //...省略
            }
            class 机关枪子弹 : Bullet
            {
                //...省略
            }
            class 狙击枪子弹 : Bullet
            {
                //...省略
            }
    
            interface  IFactory
            { 
                //...工厂接口
                Weapon CreateWeapon();
                Bullet CreateBullet();
            }
    
            class 步枪工厂 : IFactory
            {
                public Weapon CreateWeapon()
                {
                    return new 步枪();
                }
                public Bullet CreateBullet()
                {
                    return new 步枪子弹();
                }
            }
    
            class 机关枪工厂 : IFactory
            {
                public Weapon CreateWeapon()
                {
                    return new 机关枪();
                }
                public Bullet CreateBullet()
                {
                    return new 机关枪子弹();
                }
            }
    
            class 狙击枪工厂 : IFactory
            {
                public Weapon CreateWeapon()
                {
                    return new 狙击枪();
                }
                public Bullet CreateBullet()
                {
                    return new 狙击枪子弹();
                }
            }
    View Code

    "提供一个创建产品的接口来负责创建相关或依赖的对象,而不具体明确指定具体类。"这句是设计模式书上的原话,有了这个例子就好理解了,抽象工厂相对于工厂方法来说添加了"组"的概念,就不会出现"火箭筒用步枪子弹这种错误",同时也提高了扩展性,后期要是还出个什么枪套之类的对象,只需要在相应的工厂添加构造方法即可。

    写这一个故事也是纪念下通宵的那一晚,哈哈~还有以上代码并没有测试,难免有错,还有对于设计模式的理解仅代表个人观点,假如哪错了或者什么的,请大家纠正指导!

    天亮了,小白还在敲代码

    这时候老板来了,"小白,今天这么早~待会跟我一起去总部开个会。"

    小白:"老板...我能不能带个枕头去啊?"

        

        

  • 相关阅读:
    javascript判断页面第一次加载还是刷新操作【转】
    vs 2008 不能切换到设计视图的解决办法
    sql update 触发器 获得被update的行的信息
    方便winform中的数据验证,制作一个使用正则表达式验证数据的复合控件
    求一个n选x的算法
    在html链接里执行js和使用标签事件执行的不同
    咸吃萝卜淡操心:导入xlsx文件表格新增数据
    我亲爱的你,有两副面孔:表格末尾添加新内容
    Torture:跨域访问的功臣:window.name
    那么轻,那么重:图片下载与压缩包下载
  • 原文地址:https://www.cnblogs.com/hezhihao/p/4804924.html
Copyright © 2020-2023  润新知