工厂模式

所谓工厂,就是将零件组装成产品的地方。

建一个对象常常需要复杂的过程,所以不适合包含在一个复合对象中。创建对象可能会导致大量的重复代码,可能会需要复合对象访问不到的信息,也可能提供不了足够级别的抽象,还可能并不是复合对象概念的一部分。

在面向对象程序设计中,工厂通常是一个用来创建其他对象的对象。工厂是构造方法的抽象,用来实现不同的分配方案。

一般情况下,工厂模式分为三种更加细分的类型: 简单工厂、工厂方法和抽象工厂。不过,在GoF的《设计模式》一书中,它将简单工厂看作是工厂方法模式的一种特例,所以工厂模式只被分成了工厂方法抽象工厂两类。实际上,前一种分类方法更加常见。

实际上,简单工厂工厂方法原理比较简单,实际的项目也比较常用。而抽象工厂的原理稍微复杂,在实际项目相对也不常用。对于抽象工厂方法了解即可。

几个不同的设计模式都应用了工厂的概念,并可以使用在很多语言中。例如,在《设计模式》一书中,像工厂方法模式、抽象工厂模式、生成器模式,甚至是单例模式都应用了工厂的概念。

简单工厂(Simple Factory)

实现

1. 工厂类

/*** Pizza 简单工厂类*/
public class SimplePizzaFactory {/*** 根据不同pizza类型创建对应Pizza* @param type* @return*/public Pizza createPizza(String type) {if (type.equals("cheese")) {return new CheesePizza();} else if (type.equals("veggie")) {return new Veggie("veggiePizza");} else {return null;}}
}

2. 具体对象

public class Veggie extends Pizza {public Veggie(String name) {setName(name);}
}

3. Main方法

public class T {public static void main(String[] args) {// 1. 创建Pizza简单工厂SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();// 2.根据type创建PizzaPizza cheese = simplePizzaFactory.createPizza("veggie");// 3.得到Pizzacheese.toString();}
}

通过简单的if/else判断,创建对应的pizza。如果要添加新的pizza,势必要改动源码,那这违反开闭原则呢? 实际上,对于不需要频繁添加新的pizza,也是完全可以接受的。

工厂方法

定义

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类

工厂方法模式帮助我们将产品的实现使用中解耦。如果增加产品或者改变产品的实现。Creator类并不会受影响。

类图

  1. 两个类层级平等: 因为它们都有抽象类,而抽象类都有许多具体的子类,每个子类都有自己的实现。
  2. 所有的工厂都是用来封装对象的创建。
  3. 工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法的创建对象。

实现

1. 定义工厂

/*** PizzaStore 作为超类,可以被其他* 各个加盟店之间的区别在于风味不同,而其它流程我们认为是相同的*/
public abstract class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza;pizza = createPizza(type);System.out.println(pizza.getName());pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}/*** ① 工厂方法是抽象的。所以依赖子类来处理对象的创建* ② 必须返回一个产品* ③ 工厂方法有可能需要参数,也有可能不需要参数来指定所需要的产品* @param type* @return*/protected abstract Pizza createPizza(String type);
}

2. 实现工厂

/*** 芝加哥 Pizza风味店*/
public class ChicagoStylePizzaStore extends PizzaStore{@Overrideprotected Pizza createPizza(String type) {if (type.equals("cheese")) {return new ChicagoStyleCheesePizza();} else {return null;}}
}

3. Main方法

public class M {public static void main(String[] args) {System.out.println("The first customer order in Chicago pizza store");PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");System.out.println("The second customer order in NY pizza store");NYStylePizzaStore nyStylePizzaStore = new NYStylePizzaStore();nyStylePizzaStore.orderPizza("cheese");}
}

总结

优点:

  1. 调用者只需要知道名称即可,不需要了解具体实现。屏蔽具体实现细节。
  2. 扩展性高。如果想增加一个产品,只要扩展一个工厂类即可。

缺点:

  1. 每增加一个产品,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,一定程序上增加了系统的复杂度。

  2. 增加了系统具体类的依赖。

  3. 不符合开闭-原则。即对扩展开发、对修改关闭。因为每增加一个产品类,需要在工厂代码里面增加if-else判断。

  4. 简单工厂模式其实不是一个设计模式,反而比较像是一种编程习惯。

什么时候该用工厂方法模式,而非简单工厂模式?

之所以将某个代码块剥离独立为函数或类,原因是这个代码块的逻辑过于复杂,剥离之后能让代码更加清晰,更加可读、可维护。但是,如果代码块本身并不复杂,就几行代码而已,我们完全没必要将它拆分成单独的函数或者类。

基于这个设计思想,当对象的创建逻辑比较复杂,不只是简单的new一下,而是要组合其他类对象,做各种初始化操作的时候,推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂。而使用简单工厂模式,将所有的创建逻辑都放到一个工厂类中,会导致这个工厂类变得复杂。

除此之外,在某些场景下,如果对象不可复用,那工厂类每次都要返回不同对象。如果我们使用简单工厂模式实现,就只能选择第一种包含if分支逻辑的实现方式。如果我们还想避免烦人的if-else分支逻辑,推荐使用工厂方法模式

抽象工厂模式

定义

抽象工厂模式(英语:Abstract factory pattern)是一种软件开发设计模式。抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道(或关心)它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。

工厂是创建产品(对象)的地方,其目的是将产品的创建与产品的使用分离。抽象工厂模式的目的,是将若干抽象产品的接口与不同主题产品的具体实现分离开。这样就能在增加新的具体工厂的时候,不用修改引用抽象工厂的客户端代码。

使用抽象工厂模式,能够在具体工厂变化的时候,不用修改使用工厂的客户端代码,甚至是在运行时。抽象工厂模式的实质是“提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类。

(引用维基百科)

抽象工厂为产品家族提供接口。通过抽象工厂所提供的接口,可以创建产品的家族,复用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同上下文中实现各式各样的工厂,制造出各种不同的产品。

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

抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。

抽象工厂的方法经常以工厂方法的方式实现。

(引用Head First 设计模式)

抽象工厂的工作就是将抽象零件组装为抽象产品抽象是指不考虑具体怎么实现,而是仅仅只确定了方法的名字和签名

类图

  • 抽象工厂

    确定工厂的业务范围。

  • 具体工厂

    每个具体工厂对应一个产品族。具体工厂决定生产哪个具体的产品对象。

  • 抽象产品

    同一产品等级结构的抽象类。

  • 具体产品

    可供生产的具体产品。

实现

1. 定义原料工厂接口

/*** Pizza 原料工厂接口* 定义如何产生一个相关产品的家族。这个家族包含了所有制作Pizza的原料*/
public interface PizzaIngredientFactory {Dough createDough();Sauce createSauce();Cheese createCheese();
}

2. 定义原料工厂实现类

/*** 该工厂根据自身类型生产原料*/
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{@Overridepublic Dough createDough() {return new ThinCrustDough();}@Overridepublic Sauce createSauce() {return new MarinaraSauce();}@Overridepublic Cheese createCheese() {return new ReggianoCheese();}
}

3. 定义原料抽象类

/*** Cheese原料定义*/
public abstract class Cheese {}
/*** 酱料*/
public abstract class Sauce {}

4. 定义原料实现类

public class MarinaraSauce extends Sauce {}
public class ReggianoCheese extends Cheese {}

5. 定义抽象工厂

/*** Pizza店 抽象类*/
public abstract class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}/*** ① 工厂方法是抽象的。所以依赖子类来处理对象的创建* ② 必须返回一个产品* ③ 工厂方法有可能需要参数,也有可能不需要参数来指定所需要的产品* @param type* @return*/protected abstract Pizza createPizza(String type);
}

6. 定义抽象工厂实现类

/*** Pizza店具体实例* 是抽象工厂的客户*/
public class NYPizzaStore extends PizzaStore{/*** 根据类型创建Pizza* @param type* @return*/@Overrideprotected Pizza createPizza(String type) {Pizza pizza = null;// 通过PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();if (type.equals("cheese")) {pizza = new CheesePizza(ingredientFactory);pizza.setName("New York Style Cheese Pizza");return pizza;}return null;}
}

7. Main

public class T {public static void main(String[] args) {// 创建纽约Pizza店PizzaStore pizzaStore = new NYPizzaStore();// 接受订单pizzaStore.orderPizza("cheese");}
}

依赖到置原则

要依赖抽象,不要依赖具体类

指导方针

  1. 变量不可以持有具体类的引用

    如果使用new关键字,就会持有具体类的引用。你可以改用工厂来避开这样的做法。

  2. 不要让类派生自具体类

    如果派生自具体类,你就会依赖这个具体类。请派生自一个抽象(接口或抽象类)。

  3. 不要覆盖基类中已实现的方法。

    如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由所有的子类共享。

当然,完全遵守这些指导方针似乎不太可能,应该尽量达到这个原则,而不是随时都要遵循这个原则。

总结

  1. 工厂方法使用继承实现对象的创建。而抽象方法使用组合。工厂方法只负责将客户从具体类型中解耦。而抽象工厂提供一个用来创建一个产品家族的抽象类型,这个类型的子类定义了产品被产生的方法。
  2. 高层模块只需要知道自己是哪个产品族的,藉此确定具体工厂。再通过具体工厂获取对象的时候不需要知道这个对象是属于哪个具体类的,具体工厂决定使用哪个具体类。

设计模式之工厂模式(工厂方法模式、抽象工厂模式)相关推荐

  1. 设计模式:工厂方法与抽象工厂模式

    说明:这篇blog写的很好,有助于理解工厂方法与抽象工厂模式的联系与区别. 原文链接:http://blog.csdn.net/yzxz/article/details/4601152 抽象工厂模式与 ...

  2. 【设计模式】Unity3D 简单工厂、工厂(方法)、抽象工厂模式

    创建型模式-工厂三兄弟 提示:个人学习总结,如有错误,敬请指正 文章目录 创建型模式---工厂三兄弟 一.简单工厂模式 1.简单工厂模式是什么? 2.UML图 3.实现方式 二.工厂(方法)模式 1. ...

  3. C++设计模式 | Factory工厂模式(简单工厂、工厂方法、抽象工厂)

    目录 简单工厂 工厂方法 抽象工厂 学习工厂模式需要有C++虚函数 纯虚函数等相关继承与多态知识 简单工厂 在简单工厂模式中,可以根据参数的不同返回不同的实例..简单工厂模式专门定义一个类来负责创建其 ...

  4. 设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)

    工厂模式 Factory Pattern(简单工厂.工厂方法.抽象工厂) 工厂模式-创建型模式-提供了创建对象的最佳方式. 在工厂模式中,创建对象时不会对客户端暴露创建逻辑,并且是通过一个共同的接口来 ...

  5. Java设计模式-工厂模式(3)抽象工厂模式

    在Java设计模式-工厂模式(2)工厂方法模式 我们知道了工厂方法模式解决了简单工厂模式中的缺陷,做到了满足开闭原则,但是时代是进步的,进而又产生新的问题,工厂难道只能生产一种东西吗.我们所见到的工厂 ...

  6. 23招做项目——工厂模式:工厂方法和抽象工厂

    在网上的大多数资料里面,将工厂模式分为:简单工厂.工厂方法.抽象工厂,他们之间的联系(以电子厂为例)如下: 那么该文章首先讲解工厂模式是什么,为什么需要工厂模式,最后再对三种模式进行示例.该文章是23 ...

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

    工厂顾名思义就是创建产品,工厂分为三种:简单工厂,工厂方法,抽象工厂.该模式用于封装和管理对象的创建,是一种创建型模式. 1)简单工厂 该模式通过向工厂传递类型来指定要创建的对象 提供一个方法,根据类 ...

  8. 工厂模式之简单工厂、工厂方法、抽象工厂分析对比

    工厂模式有三种分类,简单工厂(也叫静态工厂).工厂方法模式.抽象工厂 一.简单工厂 简单工厂通俗的说就是提供一个类,这个类中的某个方法根据入参的不同来创建并返回实现了同一个接口的不同具体子类(产品). ...

  9. 设计模式(6)[JS版]-JavaScript如何实现抽象工厂模式?

    目录 1 学习目标 2 什么是抽象工厂模式? 3 抽象工厂模式作用 4 工厂模式参与者 5 代码实现 1 学习目标 通过本篇文章的学习,你应当掌握以下知识: 1 知道什么是抽象工厂模式? 2 掌握抽象 ...

  10. C++工厂模式(简单工厂、工厂方法、抽象工厂)

    工厂模式 前言 为什么要使用工厂模式 优点 缺点 简单工厂(Simple Factory) 代码 应用 不足 工厂方法(Factory Method) 代码 应用 不足 抽象工厂(Abstract F ...

最新文章

  1. NeurIPS 2020 Oral 论文讲解
  2. Chrome Extension 检查视图(无效)处理方法
  3. java分布式+高可用_[Java复习] 分布式高可用-Hystrix
  4. 文件系统的两种文件索引模式extent和blockmap
  5. jax_ws_对状态代码使用JAX-RS异常
  6. VS2005调试ASP.NET出现未能开始侦听端口解决办法
  7. 趣学python3(28)-pygame-蛇身随机运动(可gameover )
  8. java 监听本地端口_Java-在本地端口上侦听RTP数据包
  9. POJ 3734 Blocks 矩阵递推
  10. Web 开发的 JavaScript 框架资料收集(15款)
  11. Java体系十大组织
  12. 【插件】Unity插件UnitySRDebugger的简单使用
  13. Linux 中的 EOF 到底是什么?
  14. 基于Android开发的手持扫码枪APP(附带参考源码)
  15. HTTP POST 请求工具类
  16. 速卖通知识产权规则介绍,如何才能规避侵权的问题?
  17. 华为 两条线路负载均衡_华为无线AP4050DN接入点高可靠性,高安全性!
  18. HYKSVCAO2V4F3电液伺服阀控制器
  19. 浅谈一对一视频交友系统软件开发中UI设计的基础原则
  20. Python爬虫,抓取淘宝商品评论内容

热门文章

  1. WebAssembly emscripten工具链的搭建
  2. 仿屏保纯as随机飘动气泡
  3. ACM竞赛穷举之古堡算式
  4. web前端知识集合——javascript基础篇之javascript背景历史和运行环境(一)
  5. 风云三号卫星相关学习记录
  6. 如何找到大于或等于一个整数的最小的 2 的幂?
  7. u盘复制一直正在计算机,用U盘复制文件时电脑自动就重启是怎么回事
  8. 北京安居客二手房信息爬取
  9. Win10安装 PS6 :error16- 踩坑篇
  10. 微软服务器2016认证的考试方式,微软认证考试的几种形式