JAVA程序员Pythonic

工厂模式(简单工厂,工厂方法,抽象工厂)

2016-08-09  本文已影响375人  advancer_chen

所有文章目录: my.oschina.net/ChenTF/blog/677112

本篇文章地址: my.oschina.net/ChenTF/blog/730068

会持续的更新所有历史文章, 所以收藏的话请收藏上面的地址。

    本文将介绍简单工厂、工厂模式、抽象工厂, 所有的工厂模式都是一个目的: "为了处理创建对象的细节"。

    本文内容来源于<Head First:设计模式>, 很棒的一本书, 你值得拥有。

1. 简单工厂

1.1 背景

    当我们需要根据条件创建一系列对象时, 一般会将判断写在一个方法里面(如下面代码)。这样做在简单的稳定的业务逻辑下, 也没什么大问题, 一样可以实现功能。但是, 当我们新加了几个类时, 就需要修改业务方法的代码, 违反了"对扩展开发, 对修改关闭"原则。

    我们还有更优雅的方式, 一起来看看吧。

1.2 修改后的代码

1.2.1 业务类

1.2.2 工厂类

1.3 讲解

1.3.1 类图

    简单的说, 就是将创建对象的代码都移到了工厂类里面。那么这样有毛好处? 还多创建了一个类。

1.3.2 优点

    复用性: 如果有别的地方也用到了这些实例, 这时候是不是就复用了?

    可扩展性: 可以在工厂类中加入功能方法, 比如数据转换...

    结构清晰: 具体的业务类引用是不是变少了? 只需要引入一个工厂类即可;

    健壮性: 以后修改代码时, 直接有对应的类了, 不用怕有的改了, 有的忘记了, 改错了排查问题了。

1.3.3 讨论

    a. 之前提到"对扩展开发, 对修改关闭"。 新的方式下, 当新增/移除某个工厂时, 不也得修改工厂里面的方法吗? 谈何修改关闭?

        我对这个模式下, 该原则的理解是: 当业务改变时, 修改是必不可少的。当有新的业务扩展时, 业务的调用方是不用改变的。而简单工厂类就是为了维护对象的创建而生, 该类的修改是可以接受的。

b.将返回对象换成静态方法, 岂不更方便?

        这是很常见的技巧, 也成为静态工厂。但缺点是不能通过继承来改变创建方法的行为。

2.工厂方法模式

2.1 背景

    在简单工厂模式中, 我们将一系列对象的创建封装到一个类中, 不过现在业务扩展了, 我们需要加入更多的类。(比如纽约风味的芝士/素食/香肠/花蛤披萨,  芝加哥风味等等), 如果还使用"简单工厂"模式的话, 会是怎么样? 一个方法内有12个判断, 12个类的new, 一个类引用了12个类(如下图, 写这个例子时都看蒙了...), 所以我们需要更优雅的方式来处理当前的问题。

2.2 修改后的代码

2.2.1 抽象工厂

    在工厂中, 我们定义了子类需要实现的接口(createPizza), 和新增了一个orderPizza, 来处理共同的逻辑。

2.2.2 具体工厂

    一个"具体工厂"可以理解为一个"简单工厂", 将某一类的对象创建放在了一起。

    当我们新增一个工厂时, 只需要继承自"抽象工厂"即可, 不会修改之前的代码。

2.2.3 抽象产品

    抽象产品定义了产品的基本功能.

2.2.4 具体产品

    具体产品可以重载父类的方法, 实现个性化。

    当新增一个产品时, 只需要继承自抽象产品类就可。

2.2.5 业务调用

    当在使用时, 根据业务情况实例化对应的工厂, 然后得到对应的工厂类(多态)。

2.3 讲解

2.3.1 类图

    可以从下向上理解, YNPizzaStore引用了YN相关的产品(XYStylePizza)。然后业务扩展了, 咱们新开了ZJG, 有对应的ZJG产品。 然后就我们抽离出工厂公有的逻辑(orderPizza)与变化的部分(creatPizza), 用抽象工厂来制定协议, 对应的, 我们也将产品公共的部分抽象出来(Pizza), 就得到了这个类图。

2.3.2 优点

    之前的简单工厂有的优点, 这个模式都有(微观上看, 一个具体工厂可以理解为一个简单工厂)。工厂模式都是为了解决对象创建问题, 这个模式为简单工厂增加了扩展性。

2.3.3 讨论

a. 当只有一个工厂时, 是不是适合简单工厂, 不适合工厂模式?

    不是的。当只有一个工厂时, 用工厂模式比较好, 因为你的系统是会扩张和改变的。而当系统系统改动时, 不需要修改基础框架, 只需要继承自抽象工厂即可。工厂模式将"实现"从"使用"中解耦。

b.使用字符串传参会容易出错.

    可以使用字符串常量, 枚举等技巧。

c.简单工厂与工厂模式的区别?

    简单工厂是将全部的事情放在一个地方处理完了。而工厂方法是创建一个框架, 让子类决定如何实现。简单工厂不具备工厂方法的弹性。

d.涉及到哪些设计原则?

    依赖倒置原则: 要依赖抽象, 不要依赖具体类。

    这个原则有两条标准: 1.不能让高层组件依赖底层组件 2.无论是高层组件还是底层组件, "两者"都应该依赖于抽象。工厂模式中, 抽象的工厂和具体的工厂都依赖于抽象的产品, 而抽象的工厂是不知道具体的工厂的任何实现部分。

3. 抽象工厂

    提供一个接口, 用于创建相关或依赖对象的家族, 而不需要明确指定具体类。

3.1 背景

    工厂模式将创建单个产品的方法封装起来, 满足了单个产品的创建需求; 而如果需要将一类/多个产品的创建封装起来, 就需要抽象工厂模式。

3.2 类图

    可以简单的这样理解: 单个具体工厂类的一个方法, 可以"看做"是一个工厂模式(例如ConcreteFactory1中的CreateProducaA()), 然后具体工厂加入了多个产品, 就变成了抽象工厂。

3.3 增长的需求

    在工厂模式中, 我们将每个区域的工厂进行了区域划分(YNPizzaStore和YNStylePizza 、ZJGPizzaStore和ZJGStylePizza、ZGPizzaStore和ZGStylePizza)。现在, 每个区域的披萨都需要有不同的调料(dough、sauce和cheese), 那么该如何做?

3.3.1 调料家族

    我们将创建调理的方式通过"抽象工厂"封装了起来, 如下:

代码如下:

3.3.2 总体调整

    现在我们将调料家族加入到我们的工程中。虚线的左边是抽象工厂,提供一类原料家族的创建; 右边是工厂模式, 提供单个的产品创建。

    具体的工厂将持有对应的具体的抽象工厂, 成一对一关系(例YNPizzaStore引用YNPizzaingredientFactory)。因为原料属于产品的一部分(Pizza中的dough、sauce、cheese), 所以将具体的原料工厂传给具体的产品, 产品内调原料工厂的方法来获取对应的原料(createDough()、createSauce()、createCheese())。

代码如下:

    业务方的使用方式依然不变:

3.4 工厂模式与抽象工厂模式对比

    1. 抽象工厂可以实现多个产品的创建, 而工厂方法只能实现单个产品的创建;

    2. 抽象工厂的每个方法实际上看起来像是工厂方法;

    3. 无论是抽象工厂还是工厂模式, 都遵循依赖倒置原则, 将具体的实现从使用中解耦出来。

4. 涉及到的OO原则

    - 多用组合, 少用继承

    - 针对接口编程, 不针对实现编程

    - 为交互对象之间的松耦合涉及而努力

    - 类应该对扩展开放, 对修改关闭

    - 依赖抽象, 不要依赖具体类(依赖倒置原则)

上一篇下一篇

猜你喜欢

热点阅读