设计模式之三个工厂

简介:
在学习设计模式的过程中,看到了三个模式很相似的名称,这一篇博客,就拿它们在一起说说。
首先,这三个模式的名称分别是简单工厂、工厂方法和抽象工厂模式。对于前两个模式,感觉还比较好理解,抽象工厂模式真的很糊涂。也许,等这篇博客完工后,自己对它会更亲密些了。
首先说第一个简单工厂模式。从类型上来说,它应该属于创建型模式,但它并不包含在上篇23种模式总结的范围之中。至于为什么,自己也不清楚。这也就让自己想到了一个问题,模式的分类为什么分为创建、结构和行为三大类呢?这个问题可以在第三遍设计模式的时候思考思考。言归正传,还是回到简单工厂模式。
简单工厂模式】其是由一个工厂对象决定创建出哪一种产品类的实例。
● 该模式中包含的角色及其职责① 工厂(Creator)角色:该模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
② 抽象产品(Product)角色:该模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
③ 具体产品(Concrete Product)角色:该模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
● 该模式的最大优点工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
● 该模式的缺点由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则需要改变工厂类,也就相应地违背了开放-封闭原则。
● 该模式何时使用① 工厂类负责创建的对象比较少;
② 客户只知道传入工厂类的参数,对于如何创建对象不关心;
③ 由于很容易违反设计原则,所以一般只在很简单的情况下应用。
工厂方法模式】其定义一个用于创建对象的接口,让子类决定实例化哪一个类。其使一个类的实例化延迟到其子类。
● 该模式中包含的角色及其职责:
① 工厂接口:该模式的核心,与调用者直接交互用来提供产品。
② 工厂实现:在编程中,其决定如何实例化产品。需要有多少种产品,就需要有多少个具体的工厂实现。
③ 产品接口:其主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。
④ 产品实现:实现产品接口的具体类,决定了产品在客户端中的具体行为。
● 该模式的优点① 可以使代码结构清晰,有效地封装变化。
② 对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以。至于具体的实现,调用者无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
③ 降低耦合度。
下面,就以大鸟和小菜一开始就讨论的一个计算器的程序为例,也正是因为这个程序,我才把更加清楚它们两个。
先用简单工厂模式的方法看如何实现计算器:
首先包含一个运算类:
public class Operation
        {
            private double _numberA = 0;
            private double _numberB = 0;
            public double NumberA
            {
                get { return _numberA; }
                set { _numberA = value; }
            }
            public double NumberB
            {
                get { return _numberB; }
                set { _numberB = value; }
            }
            public virtual double GetResult()
            {
                double result = 0;
                return result;
            }
        }
其次各个具体的加减乘除类都继承运算类:
 class OperationAdd : Operation
        {
            public override double GetResult()
            {
                double result = 0;
                result = NumberA + NumberB;
                return result;
            }
        }
        class OperationSub : Operation
        {
            public override double GetResult()
            {
                double result = 0;
                result = NumberA - NumberB;
                return result;
            }
        }
最后利用一个运算工厂类负责其中的实例化:
public class OperationFactory
        {
            public static Operation createOperate(string operate)
            {
                Operation oper = null;
                switch (operate)
                {
                    case "+":
                        oper = new OperationAdd();
                        break;
                    case "-":
                        oper = new OperationSub();
                        break;
                    case "*":
                        oper = new OperationMul();
                        break;
                    case "/":
                        oper = new OperationDiv();
                        break;
                }
                return oper;
            }
        }
这样的代码确实比面向过程方便很多,但是还是存在问题,比如现在想要增加一个其他的具体运算类,如求根,这下,就必须依靠修改代码去实现实例化,这也就违背了只扩展不修改的原则。
办法总比问题多,这样,第二个说的工厂方法模式就可以用来解决问题了。
下面看如何利用工厂方法模式的方法是如何实现计算器的:
首先是前者方法中的运算类和各个具体运算类保持不变;
其次增加一个工厂接口:
interface IFactory
{
       Operation CreateOperation();
}
最后加减乘除各建一个具体的工厂去实现这个接口:
//加法类工厂
class AddFactory:IFactory
{
        public Operation CreateOperation()
        {
              return new OperationAdd();
        }
}

//减法类工厂
class SubFactory:IFactory
{
        public Operation CreateOperation()
        {
              return new OperationAdd();
        }
}
这样的代码就解决了上面去修改代码的问题,如果是要增加一个其他的具体运算类,只需要添加一个它的运算工厂以及具体运算类本身就行,也就是扩展就行。
从两者的结构图看,也更加清晰一些:
到此,我们也可以很容易发现其实它们两者是极为相似的,区别也就是:简单工厂只有三个要素,它没有工厂接口,所以在工厂实现的扩展性方面弱,可以算是工厂方法模式的简化版吧。
第三个,抽象工厂模式。
抽象工厂模式】提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
● 该模式何时使用:
当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?:读到这句话,自己才明白那么一点为什么有抽象工厂模式的出现了。
其提供两个具体工厂角色,分别对应于这两个具体产品角色,每一个具体工厂产品角色只负责一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。
● 该模式优点① 分离了具体的类;
② 使得易于交换产品系列;
③ 有利于产品的一致性。
● 该模式缺点难以支持新种类的产品
对于其优点还是有些体会的。
下面以大鸟和小菜讨论的访问数据的例子,看看它与工厂方法模式间的差别。
先看用工厂方法模式实现数据访问程序:
其中包含IUser接口(用于客户端访问)和IFactory接口(用于访问User表对象的抽象的工厂接口)
//IUser接口
interface IUser
{
     void Insert(User user);
     
     User GetUser(int id);
}
//IFactory接口
interface IFactory
{
     IUser CreateUser();
}
另外,还有具体类(AccessUser)和具体工厂(AccessFactory)。
//AccessUser类
class AccessUser:IUser
{
     public void Insert(User user)
     {
         Console.WriteLine("在Access中给User表增加一条记录");
      }
      public User GetUser(int id)
      {
          Console.WriteLine("在Access中根据ID得到User表一条记录");
          return null;
       }
}
//AccessFactory类
class AccessFactory:IFactory
{
       public IUser CreateUser()
       {
             return new AccessUser();
       }
}
这样,就用工厂方法模式实现了对数据的访问。下面同样一个问题:如果要增加某一具体类,在这里也就是指访问数据库中的其他表呢?这就必将增加一个个类对应一个个表。
这时候,抽象工厂模式就来解决问题了。它实现不光是对User表的访问,同样访问Department表的访问。
大体上都和工厂方法一致,只是它又通过增加接口来实现。同样看看两者的结构图:
最后,大鸟和小菜的对话,很好地说明了两者的区别。
小菜以为后者也是工厂方法模式的实现,大鸟的回答是:
“只有一个User类和User操作类的时候,是只需要工厂方法模式的,但是现在数据库中有很多表,而SQL Server与Access又是两大不同的分类,所以解决这种涉及到多个产品系列的问题,有一个专门的工厂模式叫做抽象工厂模式。
至此,三个工厂的总结就结束了。现在,也确实对三个工厂的了解更加深入了些。学习这三个模式,也让我们看到了遇到问题,就相应地解决问题的重要性,否则编写的程序永远不会有所进步的。
目录
相关文章
|
3月前
|
设计模式 Java
设计模式之工厂
设计模式之工厂
|
1月前
|
设计模式 Java Spring
设计模式之工厂方法
设计模式之工厂方法
设计模式之工厂方法
|
3月前
|
设计模式
从工厂到社会:探索如何应用设计模式工厂模式
从工厂到社会:探索如何应用设计模式工厂模式
|
9月前
|
设计模式 前端开发 JavaScript
前端实现设计模式之抽象工厂
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定具体的类。抽象工厂模式可以帮助我们实现对象的创建与使用的解耦,同时提供了一种灵活的方式来创建不同产品族的对象。本文将介绍如何在前端中实现抽象工厂模式,并提供具体的代码示例和解读。
|
9月前
|
设计模式 C++
设计模式工厂三姐妹
最近对于设计模式中的工厂三姐妹——大姐(抽象工厂)、二姐(工厂模式)、三姐(简单工厂),进一步学习了,以下是我的一些认识。
|
9月前
|
设计模式 前端开发 数据库
设计模式-三个工厂
设计模式-三个工厂
45 0
|
存储 设计模式 API
设计模式 | 工厂(方法)模式
工厂模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和 API 类库的核心模式。
75 1
设计模式 | 工厂(方法)模式
|
设计模式 Java
设计模式-工厂方法
设计模式-工厂方法
80 0
设计模式-工厂方法
|
设计模式 负载均衡
设计模式是什么鬼(工厂方法)
设计模式是什么鬼(工厂方法)
设计模式是什么鬼(工厂方法)
|
设计模式
工厂设计模式、简单工厂设计模式、抽象工厂设计模式(2)
工厂设计模式、简单工厂设计模式、抽象工厂设计模式(2)
82 0

热门文章

最新文章