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

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

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

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

 

     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

 

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

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

天亮了,小白还在敲代码

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

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

 

    

 

 

 

    

posted @ 2015-09-16 13:16  时噬者  阅读(1213)  评论(4编辑  收藏  举报