经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
设计模式之工厂模式
来源:cnblogs  作者:走向脚下的前方  时间:2018/12/17 9:43:22  对本文有异议

工厂模式

一:简单工厂模式

1. 问题的引出

我们打算做一个制作pizza的系统,从订购到出货,初始代码如下:

  1. public class Pizza{
  2. Pizza orderPizza(String type){
  3. Pizza pizza;
  4. // 会引起代码变化的部分
  5. if(type.equals("cheese")){
  6. pizza =new CheesePizza();
  7. }else if (type.equals("greek")){
  8. pizza=new GreekPizza();
  9. }else if(type.equals("pepperoni")){
  10. pizza=new pepperoniPizza();
  11. }
  12. //不需要改变的部分代码 这是对pizza的一系列处理
  13. pizza.prepare();
  14. pizza.bake();
  15. pizza.cut();
  16. pizza.box();
  17. return pizza;
  18. }
  19. }

客户端通过调用pizza类的orderPizza方法来创建pizza,根据type的不同来获取不同种类的pizza,然而以上的设计存在着很多问题:

  1. Pizza类中存在大量的if-else,使得整个类的代码冗长,既不容易测试又很影响性能 ,程序运行中需要做大量的条件判断。
  2. 当需要增加新的pizza的时候,必须修改Pizza类的源代码,违反了开闭原则。
  3. 客户端只能通过new关键字来创建对象,使得Pizza类和客户端耦合度很高,违反了迪米特法则。

因此我们引出了简单工厂模式,此模式能在一定程度上解决这个问题

2. 简单工厂模式概述

简单工厂模式不属于GoF23个经典设计模式,但它是学习工厂模式的基础,其思想:首先将需要创建的各种对象(各种风味pizza)封装到不同对象中,这些类称为具体产品类,将公共部分提取到抽象产品类,然后提供一个工厂类用于创建各种产品,在工厂类中提供创建产品的工厂方法,根据参数获取不同的产品对象。

其定义如下:

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

3. 简单工厂模式结构图

1544530905164

4. 简单工厂模式角色

  • Factory(工厂角色):即工厂类,负责创建所有产品实例的内部逻辑,其中提供了静态的工厂方法factoryMethod(),外界直接调用此方法来返回抽象产品类型。
  • Product(抽象产品角色):工厂类所创建的所有对象的基类,也是工厂类返回类型,符合依赖倒转原则以及开闭原则,封装了各种产品对象的公共方法。
  • ProductA(具体产品角色):由简单工厂创建得到,每个具体产品都继承或实现了抽象产品角色

在简单工厂模式中

5.简单工厂模式解决上述问题

抽象产品角色:

  1. public interface IPizza {
  2. void prepare();
  3. void bake();
  4. void cut();
  5. void box();
  6. }

具体产品A:

  1. public class PizzaA implements IPizza {
  2. @Override
  3. public void prepare() {
  4. }
  5. @Override
  6. public void bake() {
  7. }
  8. @Override
  9. public void cut() {
  10. }
  11. @Override
  12. public void box() {
  13. }
  14. }

具体产品B:

  1. public class PizzaB implements IPizza {
  2. @Override
  3. public void prepare() {
  4. }
  5. @Override
  6. public void bake() {
  7. }
  8. @Override
  9. public void cut() {
  10. }
  11. @Override
  12. public void box() {
  13. }
  14. }

工厂角色:

  1. public class SimplePizzaFactory {
  2. public static IPizza createPizza(String type){
  3. IPizza pizza=null;
  4. if(type.equals("A")){
  5. pizza =new PizzaA();
  6. }else if (type.equals("B")){
  7. pizza=new PizzaB();
  8. }
  9. return pizza;
  10. }
  11. }

客户端:

  1. public class Client {
  2. public static void main(String[] args) {
  3. IPizza pizza = SimplePizzaFactory.createPizza("A");
  4. // 创建pizza之后的工作
  5. pizza.prepare();
  6. pizza.bake();
  7. pizza.cut();
  8. pizza.box();
  9. }
  10. }

6:简单工厂模式总结

优点:

  • 简单工厂模式使得对象的创建和使用分离开来。
  • 简单工厂模式将创建对象的复杂逻辑封装起来。
  • 使用者只需要传入参数即可获得对应的产品。

缺点:

  • 违背开闭原则,一旦假如了新的产品就必须要更改工厂创建产品的逻辑。
  • 工厂类集中所有产品的创建过程,一旦类不能正常工作,将引起整个系统的故障。

二:工厂方法模式

1.问题的引出

简单工厂模式虽然解决了产品对象的创建问题,但是仍然存在很大的设计问题:当添加新的产品时候,必须通过修改客户端传过去的类型参数,其次还需要修改工厂中的if-else逻辑,显然违反了开闭原则,此外简单工厂模式所有的产品都是同一个工厂所创,工厂类职责很重,违反了单一职责原则,因此将引出第二种工厂模式->工厂方法模式。

2.工厂方法模式概述

不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构,工厂方法模式定义如下:

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。

3.工厂方法模式结构图

1544576133498

4.工厂方法模式角色

  • Product(抽象产品角色):用来定义产品的接口,是产品对象的基类。
  • ProductB(具体产品):实现了抽象产品接口
  • Factory(抽象工厂):声明了工厂方法,用于返回一个产品,抽象工厂是工厂方法模式的核心,所有的工厂类都必须实现此方法。
  • ProductAFactory(具体工厂):是抽象工厂子类,实现抽象工厂方法,返回具体的产品实例

5.工厂方法模式解决上述问题

结构如图:

1544622708998

代码如下:

抽象产品角色:

  1. public interface Pizza {
  2. // 准备
  3. void prepare();
  4. // 烘烤
  5. void bake();
  6. // 切
  7. void cut();
  8. // 装盒
  9. void box();
  10. }

具体产品角色:

  1. public class PizzaA implements Pizza {
  2. @Override
  3. public void prepare() {
  4. System.out.println("pizzaA开始准备");
  5. }
  6. @Override
  7. public void bake() {
  8. System.out.println("pizzaA开始烘烤");
  9. }
  10. @Override
  11. public void cut() {
  12. System.out.println("pizzaA开始切");
  13. }
  14. @Override
  15. public void box() {
  16. System.out.println("pizzaA开始装盒");
  17. }
  18. }
  1. public class PizzaB implements Pizza {
  2. @Override
  3. public void prepare() {
  4. System.out.println("pizzaB开始准备");
  5. }
  6. @Override
  7. public void bake() {
  8. System.out.println("pizzaB开始烘烤");
  9. }
  10. @Override
  11. public void cut() {
  12. System.out.println("pizzaB开始切");
  13. }
  14. @Override
  15. public void box() {
  16. System.out.println("pizzaB开始装盒");
  17. }
  18. }

抽象工厂:

  1. public interface PizzaFactory {
  2. Pizza createPizza();
  3. }

具体工厂角色:

  1. public class PizzaAFactory implements PizzaFactory {
  2. @Override
  3. public Pizza createPizza() {
  4. return new PizzaA();
  5. }
  6. }
  1. public class PizzaBFactory implements PizzaFactory {
  2. @Override
  3. public Pizza createPizza() {
  4. return new PizzaB();
  5. }
  6. }

客户端:

  1. public class Client {
  2. public static void main(String[] args) {
  3. // 针对抽象编程 PizzaAFactory可根据DI(依赖注入)进去
  4. // 整个客户端就不需要对修改变化,全部是针对抽象编程
  5. PizzaFactory factory = new PizzaAFactory();
  6. Pizza pizza = factory.createPizza();
  7. pizza.prepare();
  8. pizza.bake();
  9. pizza.cut();
  10. pizza.box();
  11. }
  12. }

6.工厂方法模式总结

优点:

  • 对客户端隐藏了具体产品的创建细节,无需知道传入什么参数进去。
  • 假如新产品时候,不需要更改客户端以及抽象产品角色以及抽象工厂角色,只需要添加新的工厂类以及具体产品即可,完全符合开闭原则。

缺点:

  • 如果产品的个数种类很多,那么必然会出现大量的具体工厂类,增加了系统的复杂度,会给系统带来额外的开销。

三:抽象工厂模式

1.问题的引出

工厂方法通过引入工厂等级结构,解决简单工厂职责过重(所有的产品都在一个工厂里产生)的问题,但是工厂方法会额外产生大量的工厂类,ProductA、ProductB、ProductC........,会给系统带来很大的开销,因此我们可以将相同类型的产品组成产品族,由同一个工厂生产,即抽象工厂模式的核心。

2.抽象工厂模式概述

抽象工厂模式为创建一组对象提供了解决方案,与工厂方法模式相比,抽象工厂模式中的工厂负责创建一组,其定义如下:

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。

3.抽象工厂结构图

1544713199952

  • AbstractFactory(抽象工厂):声明了一族产品的方法,每个方法对应一种产品。
  • Factory1(具体工厂):,实现了抽象工厂中的方法,生成一组具体产品,这些产品构成了产品族,某个产品都位于某个产品等级中。
  • AbstractProductA:不同产品实现或继承不同的产品接口。
  • ProductA:具体产品,实现抽象产品中的方法。

4.抽象工厂模式实例

场景如下:为了保证客户的实用安全,确保原料一致,所以需要一个工厂来生产原料,即此工厂负责原料家族中的每种原料,即工厂需要生产面团、酱料、芝士等,但是不同区域的风味不一致,抽象工厂模式设计如下图:

1544777612430

代码如下:

AbstractFactory(抽象工厂角色):

  1. //原料生产工厂 每个区域的原料工厂都需要实现此接口
  2. public abstract class PizzaIngredientFactory {
  3. //每个原料都有一个对应的方法创建该原料
  4. // 生产面团
  5. abstract Dough createDough();
  6. // 生产酱
  7. abstract Sauce createSauce();
  8. }

具体工厂:纽约原料加工厂

  1. // 纽约原料工厂
  2. public class NYPizzaIngredientFactory extends PizzaIngredientFactory {
  3. @Override
  4. Dough createDough() {
  5. return new DoughA();
  6. }
  7. @Override
  8. Sauce createSauce() {
  9. return new SauceA();
  10. }
  11. }

具体工厂:中国原料加工厂

  1. // 中国原料工厂
  2. public class ChinaIngredientFactory extends PizzaIngredientFactory {
  3. @Override
  4. Dough createDough() {
  5. return new DoughB();
  6. }
  7. @Override
  8. Sauce createSauce() {
  9. return new SauceB();
  10. }
  11. }

抽象产品角色:面团

  1. // 面团
  2. public interface Dough {
  3. }

抽象产品角色:酱料

  1. // 酱料
  2. public interface Sauce {
  3. }

具体产品角色:面团A

  1. public class DoughA implements Dough{
  2. }

具体产品角色:面团B

  1. public class DoughB implements Dough{
  2. }

具体产品角色:酱料A

  1. public class SauceA implements Sauce {
  2. }

具体产品角色:酱料B

  1. public class SauceB implements Sauce {
  2. }

5.抽象工厂方法总结

我们可以发现要是在增加新的产品族很方便,只需要扩展新的具体工厂,但是要扩展产品的等级结构(在抽象工厂中加入新的原料),会发现完全违背开闭原则,修改量巨大。

优点:

  • 增加新的产品族很方便,完全符合对修改关闭
  • 我们要替换整个产品线的话是非常容易的,只需要修改对应的具体工厂即可。

缺点:

  • 增加新的产品等级结构需要修改大量的代码,完全违背开闭原则。

四:简单工厂VS工厂方法 && 工厂方法模式VS抽象工厂模式

先来回顾一下这三者的结构图:

简单工厂模式:



工厂方法模式:



抽象工厂模式:


简单工厂模式VS工厂方法模式

  • 简单工厂模式把所有产品都放在一个工厂里生产。
  • 简单工厂违背开闭原则。
  • 工厂方法模式将产品的具体实现推迟到子类中,且针对每个产品都有对应的实现。
  • 工厂方法模式符合开闭原则。

工厂方法模式VS抽象工厂模式

  • 抽象工厂在产品族上符合开闭原则,但是在产品等级结构上违背开闭原则。
  • 抽象工厂将一系类的产品组合起来,很明显符合组合复用原则。
  • 抽象工厂可以看做是工厂方法的变形。相对于产品族来说,是工厂方法模式,相对于产品等级结构来说,也是工厂方法模式。
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号