文档章节

Thinking In Design Pattern——工厂模式演绎

 木宛城主
发布于 2015/03/02 19:39
字数 5636
阅读 1
收藏 0
点赞 0
评论 0

我始终认为学习设计模式需要怀着一颗敬畏的心去探索,这一系列23种设计模式并不是一蹴而就,都是前人根据自己的经验逐渐演化出来,所以才会形成非常经典的理论。学习设计模式,我想最好的方式是根据自己的经验逐渐来推导它,这样你才理解了其中奥妙,而不是靠记忆背住了它,所以,这篇博文主要分析三种工厂模式的演变过程:

我们先举一个最平常例子——写一个最简单的计算器,我们可能非常快就完成了第一个版本:

来实现吧,简易计算器

namespace 工厂模式之简单计算器
{
    /// <summary>
    /// 版本一
    /// </summary>
    class Program
    {
        //很差劲,统一交给了Main函数,没有重用的地方,不能体现重用性
        //这是面向过程编程
        //客户端耦合性很高,想扩展其余运算靠修改Swith语句
        //总之就是一坨代码

        static void Main(string[] args)
        {
            Console.WriteLine("请输入一个数:a=");
            int a = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("请输入另一个数:b=");
            int b = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("请输入操作运算符");
            string op = Console.ReadLine();
            int result = 0;
            
            switch (op)
            {
                case "+":
                    result = a + b;
                    break;
                case "-":
                    result = a - b;
                    break;
                case "*":
                    result=a*b;
                    break;
                case "/":
                    result = a / b;
                    break;
                default:
                    break;
            }
            Console.WriteLine("{0}{1}{2}={3}",a,op,b,result);
            Console.ReadKey();
        }
    }
}

优秀的程序员依靠清晰的逻辑思维方能拨开云雾见晨曦,对于第一版本,有着各种各样的差强人意的设计,所以第二版本,我们有的放矢,对第一版本稍作修改。

代码能否复用性

namespace 工厂模式Demo2
{
    /// <summary>
    /// 版本二:考虑方法的重用性,注意这儿依旧是面向过程运算,不是面向对象
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入一个数:a=");
            int a = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("请输入另一个数:b=");
            int b = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("请输入操作运算符");
            string op = Console.ReadLine();
            //这儿对第一版本进行修改,体现了方法的重用性
            int result = Calculate(a, b, op);
            Console.WriteLine("{0}{1}{2}={3}", a, op, b, result);
            Console.ReadKey();
        }

        private static int Calculate(int a, int b, string op)
        {
            int result = 0;

            switch (op)
            {
                case "+":
                    result = a + b;
                    break;
                case "-":
                    result = a - b;
                    break;
                case "*":
                    result = a * b;
                    break;
                case "/":
                    result = a / b;
                    break;
                default:
                    break;
            }
            return result;
        }
    }
}

版本二虽然比版本一稍稍先进了,但依然是面向过程编程,看来写一个令人满意的计算器还是有点麻烦的,希望版本三引入面向对象思想,希望能够让我满意。

忘记面向过程吧,面向对象思想的引入

namespace 工厂模式Demo3
{
    /// <summary>
    /// 增加一个Calculator计算父类
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入一个数A=");
            int a = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入另一个数B=");
            int b = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入运算符:");
            string op = Console.ReadLine();
            int result = 0;
            //重复代码过多
            switch (op)
            {
                case "+":
                    AddCalculate calcAdd = new AddCalculate();
                    calcAdd.NumberA = a;
                    calcAdd.NumberB = b;
                    result = calcAdd.GetResult;
                    break;
                case "-":
                    SubCalculate calcSub = new SubCalculate();
                    calcSub.NumberA = a;
                    calcSub.NumberB = b;
                    result = calcSub.GetResult;
                    break;
                case "*":
                    MultiCalculate calcMulti = new MultiCalculate();
                    calcMulti.NumberA = a;
                    calcMulti.NumberB = b;
                    result = calcMulti.GetResult;
                    break;
                case "/":
                    DivisCalculate calcDiv = new DivisCalculate();
                    calcDiv.NumberA = a;
                    calcDiv.NumberB = b;
                    result = calcDiv.GetResult;
                    break;
                
                default:
                    break;
            }
            Console.WriteLine("{0}{1}{2}={3}",a,op,b,result);
            Console.ReadLine();
        }
    }
    abstract class Calculate
    {
        protected int numberA;
        //属性:封装字段
        public int NumberA
        {
            get { return numberA; }
            set { numberA = value; }
        }
        protected int numberB;
        //属性:封装字段
        public int NumberB
        {
            get { return numberB; }
            set { numberB = value; }
        }
        /// <summary>
        /// 抽象属性:由子类对象来完成计算
        /// </summary>
        public abstract int GetResult { get; }

    }
    /// <summary>
    /// 加法运算类
    /// </summary>
    class AddCalculate : Calculate
    {
        public override int GetResult
        {
            get {return base.numberA + base.numberB;  }
        }
    }
    /// <summary>
    /// 减法运算类
    /// </summary>
    class SubCalculate : Calculate
    {public override int GetResult
        {
            get { return base.numberA - base.numberB; }
        }
    }
    /// <summary>
    /// 乘法运算类
    /// </summary>
    class MultiCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA * base.numberB; }
        }
    }
    /// <summary>
    /// 除法运算类
    /// </summary>
    class DivisCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA / base.numberB; }
        }
    }
}

版本三相对于版本二来说是质的飞跃,由面向过程编程转向了面向对象编程,但Swith里面有太多的重复代码,仅仅只有 AddCalculate calcAdd = new AddCalculate()这些实例化语句在改变。所以下一个版本就是看能否抽象出一个然后父类采用里氏替换原则来替换之前重复代码。

多态,简化代码大杀器

namespace 工厂模式Demo4
{
    /// <summary>
    /// 这个版本较上个版本也是质的飞跃,引入了多态这个概念。
    /// 但是发现客户端耦合度还是高,除了要认识父类外,还要认识加减乘除类
    /// 所以尽量来解耦,就像我去商店买笔,没必要知道笔是怎么制造的
    /// 也就是说客户端只要和父类耦合即可,子类没必要和客户端耦合
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入一个数A=");
            int a = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入另一个数B=");
            int b = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入运算符:");
            string op = Console.ReadLine();
            int result = 0;
            //对上一版本进行修改,定义了父类
            Calculate calc = null;

            switch (op)
            {
                case "+":
                    calc = new AddCalculate();//多态
                    break;
                case "-":
                    calc = new SubCalculate();
                    break;
                case "*":
                    calc = new MultiCalculate();
                    break;
                case "/":
                    calc = new DivisCalculate();
                    break;

                default:
                    break;
            }
            calc.NumberA = a;
            calc.NumberB = b;
            result=calc.GetResult;
            Console.WriteLine("{0}{1}{2}={3}", a, op, b, result);
            Console.ReadLine();
        }
    }
    abstract class Calculate
    {
        protected int numberA;
        //属性:封装字段
        public int NumberA
        {
            get { return numberA; }
            set { numberA = value; }
        }
        protected int numberB;
        //属性:封装字段
        public int NumberB
        {
            get { return numberB; }
            set { numberB = value; }
        }
        /// <summary>
        /// 抽象属性:由子类对象来完成计算
        /// </summary>
        public abstract int GetResult { get; }

    }
    /// <summary>
    /// 加法运算类
    /// </summary>
    class AddCalculate : Calculate
    {
        public override int GetResult
        {
            get
            {
               
                return base.NumberA + base.NumberB;
            }
        }
    }
    /// <summary>
    /// 减法运算类
    /// </summary>
    class SubCalculate : Calculate
    {
      
        public override int GetResult
        {
            get { return base.NumberA - base.numberB; }
        }
    }
    /// <summary>
    /// 乘法运算类
    /// </summary>
    class MultiCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA * base.numberB; }
        }
    }
    /// <summary>
    /// 除法运算类
    /// </summary>
    class DivisCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA / base.numberB; }
        }
    }
}

 

这个版本在上一个版本的基础上增加了多态,简化了很多重复代码,看似完美,但仍旧有缺陷:客户端耦合度还是高,除了要认识父类外,还要认识加减乘除类,所以尽量来解耦,就像我去商店买笔,没必要知道笔是怎么制造的,也就是说客户端只要和父类耦合即可,子类没必要和客户端耦合。所以为了解耦,引入一个第三方工厂类,将和客户端耦合的加减乘除类封装到我们的工厂类中(去耦合,封装复杂度),这就是简单工厂模式,其特征:

  • 只有一个工厂(具体的,没有抽象)
  • 只生产一种产品(抽象的产品,基类)
  • 这种产品可以有多种具体产品类型(派生)

注意:由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。

质的飞跃,简单工厂模式的运用

namespace 简单工厂模式
{
    /// <summary>
    /// 简单工厂特点:
    /// 1.只有一个工厂(不是抽象)
    /// 2.只有一种类型的产品(基类,与子类数量无关)
    /// 3.一个工厂只生产一种类型产品
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入一个数A=");
            int a = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入另一个数B=");
            int b = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入运算符:");
            string op = Console.ReadLine();
            int result = 0;
         
            
            Calculate calc=SimpleFactory.GetCalc(op);//解耦了,客户端不认识具体的类,用简单工厂类封装了这种复杂度,也就是去耦合度。这样客户端和工厂、抽象的产品耦合了。
            calc.NumberA=a;
            calc.NumberB=b;
            result = calc.GetResult;
            Console.WriteLine("{0}{1}{2}={3}", a, op, b, result);
            Console.ReadLine();
        }
    }
    /// <summary>
    ///创建一个简单工厂
    /// </summary>
    static class SimpleFactory
    { 
        /// <summary>
        /// 简单工厂封装了对象创建的复杂度
        /// </summary>
        /// <param name="op"></param>
        /// <returns>产品的抽象</returns>
        public static Calculate GetCalc(string op)
        {
            Calculate calc = null;
            
            switch (op)
            {
                case "+":
                    calc = new AddCalculate();//多态
                    break;
                case "-":
                    calc = new SubCalculate();
                    break;
                case "*":
                    calc = new MultiCalculate();
                    break;
                case "/":
                    calc = new DivisCalculate();
                    break;

                default:
                    break;
            }
            return calc;
        }
    }



    abstract class Calculate
    {
        protected int numberA;
        //属性:封装字段
        public int NumberA
        {
            get { return numberA; }
            set { numberA = value; }
        }
        protected int numberB;
        //属性:封装字段
        public int NumberB
        {
            get { return numberB; }
            set { numberB = value; }
        }
        /// <summary>
        /// 抽象属性:由子类对象来完成计算
        /// </summary>
        public abstract int GetResult { get; }

    }
    /// <summary>
    /// 加法运算类
    /// </summary>
    class AddCalculate : Calculate
    {
        public override int GetResult
        {
            get
            {

                return base.NumberA + base.NumberB;
            }
        }
    }
    /// <summary>
    /// 减法运算类
    /// </summary>
    class SubCalculate : Calculate
    {

        public override int GetResult
        {
            get { return base.NumberA - base.numberB; }
        }
    }
    /// <summary>
    /// 乘法运算类
    /// </summary>
    class MultiCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA * base.numberB; }
        }
    }
    /// <summary>
    /// 除法运算类
    /// </summary>
    class DivisCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA / base.numberB; }
        }
    }
}

ok,到目前为止我们再和第一版的计算器比较下,原先那个版本简直是A Piece Of XXX。简单工厂其实不是一种设计模式,这不重要,重要的是你是否能理解并为自己运用。我们再回过头来,看看我们的简单计算器是否还有地方要改进,这就要引出我们下一个话题,简单工厂的局限性:

  • 由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了(也违反了开放封闭原则,对修改封闭,对扩展开放)。
  • 当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;

这些缺点在工厂方法模式中得到了一定的克服。

迷途知返,拨开云雾见工厂方法

什么是工厂方法——

定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod使得一个类的实例化延迟到子类。——GOF 《设计模式》

工厂方法的概念很抽象,我们对其进行解释:

工厂方法模式对简单工厂模式进行了抽象(想想看,简单工厂模式里工厂是个具体类),Factory Method模式的两种情况:

  • 一:Creator类是一个抽象类且它不提供它所声明的工厂方法的实现,比如有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成(体现了延迟性)。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一种类型抽象产品,一个具体工厂对应一个具体产品(体现了类的单一职责),这个具体的工厂就负责生产对应的产品。
  • 二:Creator类是一个具体的类且它提供一个工厂方法的缺省实现。

看了上面那段话,晕了吗,还是代码解释吧(第一种情况:Creator是抽象的类,所以我的工厂类定义为是抽象类[即下面案例中:运算AbstractFactory]):

namespace 工厂方法
{

    //Factory Method模式主要用于隔离类对象的使用者(Main函数)和具体类型(我在Main函数里只知道抽象的父类,也不知道具体的实现子类)之间的耦合关系(迪米特法则:用户知道越少越好,这样封装性越高)。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入A:");
            int a = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入B:");
            int b = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入运算符");
            
            string op = Console.ReadLine();
            
            运算AbstractFactory factory = null;
            Calculate calc = null;


            #region 这儿就是局部化
            //注意:这里的switch不是必须的,可以利用反射技术动态创建工厂的实例
            //反射详见抽象工厂
            switch (op)
            {
                case "+":
                    factory = new 加法Factory();

                    break;
                case "-":
                    factory = new 减法Factory();
                    break;
                case "*":
                    factory = new 乘法Factory();
                    break;
                case "/":
                    factory = new 除法Factory();
                    break;
                default:
                    break;
            } 
            #endregion

            calc = factory.GetCalc();
            calc.NumberA = a;
            calc.NumberB = b;
            int result = calc.GetResult;
            Console.WriteLine(result);
            Console.ReadKey();

        }
    }
   
    //1.Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略(开放封闭原则思想),较好地解决了这种紧耦合关系。(和简单工厂比较)
    //2.工厂类和产品类往往可以依次对应,即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品(体现了类的单一职责),这个具体的工厂就负责生产对应的产品。
    abstract class 运算AbstractFactory
    {
      
        public abstract Calculate GetCalc();
    }


    //通过继承来扩展,而非是修改Swith语句那样去修改————开放封闭原则,对扩展开放,对修改封闭
    class 加法Factory : 运算AbstractFactory
    {
        public override Calculate GetCalc()
        {
            return new AddCalculate();//这里体现了推迟.../延迟到工厂子类 子类辅助帮助父类实现具体创建哪个对象,也就是New XXCalculate()
        }
    }
    class 减法Factory : 运算AbstractFactory 
    {
        public override Calculate GetCalc()
        {
            return new SubCalculate();
        }
    }
    class 乘法Factory : 运算AbstractFactory
    {
        public override Calculate GetCalc()
        {
            return new MultiCalculate();
        }
    }
    class 除法Factory : 运算AbstractFactory
    {
        public override Calculate GetCalc()
        {
            return new DivisCalculate();
        }
    }
    ///////////////产品没变化//////////////

   //对产品的抽象
    abstract class Calculate
    {
        protected int numberA;
        //属性:封装字段
        public int NumberA
        {
            get { return numberA; }
            set { numberA = value; }
        }
        protected int numberB;
        //属性:封装字段
        public int NumberB
        {
            get { return numberB; }
            set { numberB = value; }
        }
        /// <summary>
        /// 抽象属性:由子类对象来完成计算
        /// </summary>
        public abstract int GetResult { get; }

    }
    /// <summary>
    /// 加法运算类
    /// </summary>
    class AddCalculate : Calculate
    {
        public override int GetResult
        {
            get
            {

                return base.NumberA + base.NumberB;
            }
        }
    }
    /// <summary>
    /// 减法运算类
    /// </summary>
    class SubCalculate : Calculate
    {

        public override int GetResult
        {
            get { return base.NumberA - base.numberB; }
        }
    }
    /// <summary>
    /// 乘法运算类
    /// </summary>
    class MultiCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA * base.numberB; }
        }
    }
    /// <summary>
    /// 除法运算类
    /// </summary>
    class DivisCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA / base.numberB; }
        }
    }

}

第二种情况:Creator是一个具体的类且它提供一个工厂方法的缺省实现。

namespace 工厂方法3
{

   
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入A:");
            int a = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入B:");
            int b = int.Parse(Console.ReadLine());
            Console.WriteLine("请输入运算符");

            string op = Console.ReadLine();

            运算Factory factory = null;
            Calculate calc = null;


            #region 这儿就是局部化
            //注意:这里的switch不是必须的,可以利用反射技术动态创建工厂的实例

            switch (op)
            {
                case "+":
                    factory = new 加法Factory();

                    break;
                case "-":
                    factory = new 减法Factory();
                    break;
                case "*":
                    factory = new 乘法Factory();
                    break;
                case "/":
                    factory = new 除法Factory();
                    break;
                default:
                    break;
            }
            #endregion

            calc = factory.GetCalc();
            calc.NumberA = a;
            calc.NumberB = b;
            int result = calc.GetResult;
            Console.WriteLine(result);
            Console.ReadKey();

        }
    }

    //注意:Creator不是抽象类了,而是一个具体的类
     class 运算Factory
    {

        public virtual Calculate GetCalc()
        {
            return new AddCalculate();//默认缺省实现
        }
    }


    //通过继承来扩展,而非是修改Swith语句那样去修改————开放封闭原则,对扩展开放,对修改封闭
    class 加法Factory : 运算Factory
    {
        
    }
    class 减法Factory : 运算Factory
    {
        public override Calculate GetCalc()
        {
            return new SubCalculate();
        }
    }
    class 乘法Factory : 运算Factory
    {
        public override Calculate GetCalc()
        {
            return new MultiCalculate();
        }
    }
    class 除法Factory : 运算Factory
    {
        public override Calculate GetCalc()
        {
            return new DivisCalculate();
        }
    }
    ///////////////产品没变化//////////////

    //对产品的抽象
    abstract class Calculate
    {
        protected int numberA;
        //属性:封装字段
        public int NumberA
        {
            get { return numberA; }
            set { numberA = value; }
        }
        protected int numberB;
        //属性:封装字段
        public int NumberB
        {
            get { return numberB; }
            set { numberB = value; }
        }
        /// <summary>
        /// 抽象属性:由子类对象来完成计算
        /// </summary>
        public abstract int GetResult { get; }

    }
    /// <summary>
    /// 加法运算类
    /// </summary>
    class AddCalculate : Calculate
    {
        public override int GetResult
        {
            get
            {

                return base.NumberA + base.NumberB;
            }
        }
    }
    /// <summary>
    /// 减法运算类
    /// </summary>
    class SubCalculate : Calculate
    {

        public override int GetResult
        {
            get { return base.NumberA - base.numberB; }
        }
    }
    /// <summary>
    /// 乘法运算类
    /// </summary>
    class MultiCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA * base.numberB; }
        }
    }
    /// <summary>
    /// 除法运算类
    /// </summary>
    class DivisCalculate : Calculate
    {
        public override int GetResult
        {
            get { return base.numberA / base.numberB; }
        }
    }

}

 OK,其实工厂方法不复杂,注意其特点:只有一种产品。

在以下情况下,适用于工厂方法模式:

  • 1. 当一个类不知道它所必须创建的对象的类的时候。
  • 2. 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候(通过反射技术或者Swith语句来实现局部化变化)。 

工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现“开-闭 原则”,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。

到目前为止,我们的计算器已经完美了,计算器也将告一段落了。接下来我们再来探讨一下,如果产品总类增加,怎样来设计我们的应用程序呢?接下来我们看抽象工厂模式(抽象工厂模式针对的是多个产品等级结构)。

柳暗花明又一村:抽象工厂+工厂方法

什么是抽象工厂——

提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。 ——GOF 《设计模式》

 

 

M系列*N产品

通过这幅图也可以发现: Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动(因为添加一个新的产品类型需要修改太多的地方了)

抽象工厂实现要点:

  • 抽象工厂将产品对象的创建延迟到它的具体工厂的子类。
  • 通常在运行时刻创建一个具体工厂类的实例(反射),这一具体工厂的创建具有特定实现的产品对象,为创建不同的产品对象,客户应使用不同的具体工厂。
  • 把工厂作为单例,一个应用中一般每个产品系列只需一个具体工厂的实例,因此,工厂通常最好实现为一个单例模式(反射耗费性能)。
  • 创建产品,抽象工厂仅声明一个创建产品的接口,真正创建产品是由具体工厂类创建的,最通常的一个办法是为每一个产品定义一个工厂方法(生产产品),一个具体的工厂将为每个产品重定义该工厂方法以指定产品,虽然这样的实现很简单,但它要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。

具体代码实现:

namespace 抽象工厂Form
{

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Assembly assembly = null;
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "exe文件|*.exe|dll文件|*.dll";
            dialog.InitialDirectory = Application.StartupPath;
            if (dialog.ShowDialog()==DialogResult.OK)
            {
                //反射
                assembly = System.Reflection.Assembly.LoadFile(dialog.FileName);
                this.comboBox1.Items.Clear();
                foreach (var item in assembly.GetTypes())
                {
                    if (item.IsSubclassOf(typeof(SportShop)))
                    {
                        //将SportShop的两个子类加入下拉列表
                        this.comboBox1.Items.Add(item);
                    }
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Clothes clothes = null;
            Hat hat = null;
            SportShop shop = null;
            string typeName = ((Type)this.comboBox1.SelectedItem).FullName;
            //运行时刻创建一个具体工厂类的实例,这一具体工厂的创建具有特定实现的产品对象,为创建不同的产品对象,客户应使用不同的具体工厂(通过配置文件反射)
            shop = Factory.CreateShop(assembly, typeName);
            clothes = shop.SellClothes();
            hat = shop.SellHat();
            MessageBox.Show(string.Format("衣服:{0},帽子:{1}", clothes, hat));
        }
      
    }
      /// <summary>
        /// 抽象的产品A
        /// </summary>
        abstract class Clothes
        {

        }
        /// <summary>
        /// 抽象的产品B
        /// </summary>
        abstract class Hat
        {

        }
        /// <summary>
        /// Nike产品A(系列1的产品A)
        /// </summary>
        class NikeClothes : Clothes
        {
            public override string ToString()
            {
                return "Nike衣服";
            }
        }
        /// <summary>
        /// Nike产品B(系列1的产品B)
        /// </summary>
        class NikeHat : Hat
        {
            public override string ToString()
            {
                return "Nike帽子";
            }
        }
        /// <summary>
        /// LiNing产品A(系列2的产品A)
        /// </summary>
        class LiNingClothes : Clothes
        {
            public override string ToString()
            {
                return "LiNing衣服";
            }
        }
        /// <summary>
        /// LiNing产品B(系列2的产品B)
        /// </summary>
        class LiNingHat : Hat
        {
            public override string ToString()
            {
                return "LiNing帽子";
            }
        }
        /// <summary>
        /// 抽象的工厂,负责规定创建产品(多种)
        /// </summary>
        abstract class SportShop
        {
            /// <summary>
            /// 创建产品A
            /// </summary>
            /// <returns></returns>
            public abstract Clothes SellClothes();
            /// <summary>
            /// 创建产品B
            /// </summary>
            /// <returns></returns>
            public abstract Hat SellHat();
        }
        /// <summary>
        /// 具体的系列1工厂
        /// 把工厂作为单例,一个应用中一般每个产品系列只需一个具体工厂的实例,因此,工厂通常最好实现为一个单例模式。 
        /// </summary>
        class NikeFactory : SportShop
        {
            
            //创建产品,抽象工厂仅声明一个创建产品的接口,真正创建产品是由具体工厂类创建的,最通常的一个办法是为每一个产品定义一个工厂方法,一个具体的工厂将为每个产品重定义该工厂方法以指定产品,虽然这样的实现很简单,但它要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。 
            public override Clothes SellClothes()//抽象工厂将产品对象的创建延迟到它的具体具体工厂子类中
            {
                return new NikeClothes();
            }
            public override Hat SellHat()
            {
                return new NikeHat();
            }
        }
        /// <summary>
        /// 具体的系列2的工厂
        /// </summary>
        class LiNingFactory : SportShop
        {
            public override Clothes SellClothes()
            {
                return new LiNingClothes();
            }
            public override Hat SellHat()
            {
                return new LiNingHat();
            }
        }
        /// <summary>
        /// Abstract Factory模式经常和Factory Method模式共同组合来应对“对象创建”的需求变化。
        ///这里的处理很经典: 把SportShop可以看成是产品(之前还是系列),所以这儿是工厂方法
        /// </summary>
        static class Factory
        {
            public static SportShop CreateShop(Assembly assembly,string typeName)
            {
                //反射,当然Swith...Case也OK
                return (SportShop)assembly.CreateInstance(typeName);
                
                //switch (typeName)
                //{
                    
                //    case "Nike...":
                //        return new NikeFactory();
                //    case "LiNing":
                //        return new LiNingFactory();
                //    default:
                //        break;
                //}
            }
        }
}

对抽象工厂的总结:

  • 如果没有应对“多系列对象构建”的需求变.化,则没有必要使用Abstract Factory模式,这时候使用简单的静态工厂完全可以。
  • “ 系列对象”指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的“道路”与“房屋”的依赖,“道路”与“地道”的依赖。
  • Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。(案例图体现了
  • Abstract Factory模式经常和Factory Method模式共同组合来应对“对象创建”的需求变化。(代码里体现了)

 总结

简单工厂模式:一个具体工厂+一种产品

工厂方法模式:一个抽象工厂(多个具体工厂)+一种产品

抽象工厂模式:一个抽象工厂(M个系列工厂)+N种产品

千万别死记硬背设计模式,以不同的视角看同一个类,会有不同的处理,如:上述代码把SportShop可以看成是产品(之前还是系列)。

3x:)

© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 222
码字总数 199010
作品 0
黄浦
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho ⋅ 04/09 ⋅ 0

【设计模式】——命令模式

【情景展示】 在网络出现之前,我们的日常生活中,人与人的交际,一般使用语言沟通,然而社会在进步,随着城市化进程的加快,我们的生活发生了巨大的变化,如今的社会,人与人之间的交流方式...

u013043341 ⋅ 02/02 ⋅ 0

设计模式梳理(一)

设计模式梳理(一) 总体来说设计模式分为三大类: @案例源码地址:https://gitlab.com/lxqxsyu/DisgnPattern 创建型模式 简单工厂模式 工厂类是整个模式的关键。它包含必要的判断逻辑,能够...

lxq_xsyu ⋅ 2017/11/02 ⋅ 0

C#设计模式(2)——简单工厂模式

一、引言   这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式——简单工...

技术小胖子 ⋅ 2017/11/08 ⋅ 0

Java 设计模式(14) —— 复合模式

一、复合模式 模式常一起使用,组合在一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式,能解决一般性或一系列的问题 二、示例 本次设计模式讲解中无代码示例,由于复合模式是...

磊_lei ⋅ 05/26 ⋅ 0

从ES6重新认识JavaScript设计模式(三): 建造者模式

1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示。 建造者模式的特点是分步构建一个复杂的对象,可以用不同组合或顺序...

Lee_tanghui ⋅ 06/02 ⋅ 0

JavaScript设计模式之观察者模式

前言 准备研究一下MVVM的一些东西,由于MVVM运用了观察者模式的思想,因此翻开了《JavaScript设计模式与开发实践》一书,将观察者模式学习了一遍,顺便有对一些常用的设计模式进行一些了解,...

Srtian ⋅ 05/22 ⋅ 0

设计模式分类与原则

创建型模式 这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 工厂模式(...

晨猫 ⋅ 03/12 ⋅ 0

JS单例模式《JavaScript设计模式与开发实践》阅读笔记

此文仅记录本人阅读《JavaScript设计模式与开发实践》这个本时的感受,感谢作者曾探写出这么好的一本书。如有冒犯,如有错误,请联系本人:luogao_lg@sina.com处理。 这一章让我知道了单例模...

RoyLuo ⋅ 05/17 ⋅ 0

ES7 Decorator 装饰者模式

原作者:玄农 装饰模式 设计模式大家都有了解,网上有很多系列教程,比如 JS设计模式等等。 这里只分享 装饰者模式 以及在 如何使用 ES7 的 概念 装饰模式 v.s. 适配器模式 装饰模式和适配器...

_朴灵_ ⋅ 05/14 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

win10怎么彻底关闭自动更新

win10自带的更新每天都很多,每一次下载都要占用大量网络,而且安装要等得时间也蛮久的。 工具/原料 Win10 方法/步骤 单击左下角开始菜单点击设置图标进入设置界面 在设置窗口中输入“服务”...

阿K1225 ⋅ 今天 ⋅ 0

Elasticsearch 6.3.0 SQL功能使用案例分享

The best elasticsearch highlevel java rest api-----bboss Elasticsearch 6.3.0 官方新推出的SQL检索插件非常不错,本文一个实际案例来介绍其使用方法。 1.代码中的sql检索 @Testpu...

bboss ⋅ 今天 ⋅ 0

informix数据库在linux中的安装以及用java/c/c++访问

一、安装前准备 安装JDK(略) 到IBM官网上下载informix软件:iif.12.10.FC9DE.linux-x86_64.tar放在某个大家都可以访问的目录比如:/mypkg,并解压到该目录下。 我也放到了百度云和天翼云上...

wangxuwei ⋅ 今天 ⋅ 0

PHP语言系统ZBLOG或许无法重现月光博客的闪耀历史[图]

最近在写博客,希望通过自己努力打造一个优秀的教育类主题博客,名动江湖,但是问题来了,现在写博客还有前途吗?面对强大的自媒体站点围剿,还有信心和可能型吗? 至于程序部分,我选择了P...

原创小博客 ⋅ 今天 ⋅ 0

IntelliJ IDEA 2018.1新特性

工欲善其事必先利其器,如果有一款IDE可以让你更高效地专注于开发以及源码阅读,为什么不试一试? 本文转载自:netty技术内幕 3月27日,jetbrains正式发布期待已久的IntelliJ IDEA 2018.1,再...

Romane ⋅ 今天 ⋅ 0

浅谈设计模式之工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻...

佛系程序猿灬 ⋅ 今天 ⋅ 0

Dockerfile基础命令总结

FROM 指定使用的基础base image FROM scratch # 制作base image ,不使用任何基础imageFROM centos # 使用base imageFROM ubuntu:14.04 尽量使用官方的base image,为了安全 LABEL 描述作...

ExtreU ⋅ 昨天 ⋅ 0

存储,对比私有云和公有云的不同

导读 说起公共存储,很难不与后网络公司时代的选择性外包联系起来,但尽管如此,它还是具备着简单和固有的可用性。公共存储的名字听起来也缺乏专有性,很像是把东西直接堆放在那里而不会得到...

问题终结者 ⋅ 昨天 ⋅ 0

C++难点解析之const修饰符

C++难点解析之const修饰符 c++ 相比于其他编程语言,可能是最为难掌握,概念最为复杂的。结合自己平时的C++使用经验,这里将会列举出一些常见的难点并给出相应的解释。 const修饰符 const在c...

jackie8tao ⋅ 昨天 ⋅ 0

聊聊spring cloud netflix的HystrixCommands

序 本文主要研究一下spring cloud netflix的HystrixCommands。 maven <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-clo......

go4it ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部