问题:

在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则。

定义:

定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类。此时工厂和产品都具有相同的继承结构,抽象产品类与抽象工厂对应,具体的产品类和具体的工厂类对应。工厂方法模式又称为:工厂模式(Factory Pattern)、虚拟构造器模式(Virtual Constructor Pattern)、多态工厂模式(Polymorphic Factory Pattern)等。

结构图:

  • Product:抽象产品类,是所有具体产品的超类型,封装了具体产品的公共方法。
  • ConcreteProduct:具体产品类,实现了抽象产品类的接口,和具体工厂一一对应。
  • Factory:抽象工厂类,定义了返回抽象产品类的工厂方法,是工厂方法模式的核心。
  • ConcreteFactory:具体工厂类,实现了抽象工厂定义的工厂方法,由客户端直接调用,返回其对应的具体产品类。

注意:

  • 为了让系统有更好的灵活性和可扩展性,可以使用XML技术和反射技术让客户端通过配置文件指定具体工厂类。

  • 可以在抽象工厂中定义多个重载的工厂方法,包含不同的业务逻辑,来满足对不同产品对象的需求。例如可以传入数据库配置信息,文件配置信息等。

  1. interface LoggerFactory {
  2. public Logger createLogger();
  3. public Logger createLogger(String args);
  4. public Logger createLogger(Object obj);
  5. }
  6. class DatabaseLoggerFactory implements LoggerFactory {
  7. public Logger createLogger() {
  8. //使用默认方式连接数据库,代码省略
  9. Logger logger = new DatabaseLogger();
  10. //初始化数据库日志记录器,代码省略
  11. return logger;
  12. }
  13. public Logger createLogger(String args) {
  14. //使用参数args作为连接字符串来连接数据库,代码省略
  15. Logger logger = new DatabaseLogger();
  16. //初始化数据库日志记录器,代码省略
  17. return logger;
  18. }
  19. public Logger createLogger(Object obj) {
  20. //使用封装在参数obj中的连接字符串来连接数据库,代码省略
  21. Logger logger = new DatabaseLogger();
  22. //使用封装在参数obj中的数据来初始化数据库日志记录器,代码省略
  23. return logger;
  24. }
  25. }
  • 还可以由工厂直接调用具体产品的业务方法,而隐藏工厂创建具体实例的方法。
  1. abstract class LoggerFactory {
  2. //在工厂类中直接调用日志记录器类的业务方法writeLog()
  3. public void writeLog() {
  4. Logger logger = this.createLogger();
  5. logger.writeLog();
  6. }
  7. public abstract Logger createLogger();
  8. }

优点:

  • 利用工厂的工厂方法类创建具体的实例,隐藏了具体实例的创建细节,无需知道具体实例的类名,只需关心对应工厂。
  • 加入新的产品类是,只需要同时加入工厂类就可以实现扩展。如果利用反射和XML技术,不需要修改任何源码,符合“开闭原则”

缺点:

  • 系统中类的个数显著增加,不利于系统的维护,增加系统编译和运行的开销。

适用场景

  • 具体产品类数目不多,客户不需要知道具体产品类的详细信息,只需要知道具体对应的工厂。

实例:

FactoryMethodPattern.java

六个创建模式之工厂方法模式(Factory Method Pattern)的更多相关文章

  1. 使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

    本文源自深入浅出设计模式. 只不过我是使用C#/.NET Core实现的例子. 前言 当你看见new这个关键字的时候, 就应该想到它是具体的实现. 这就是一个具体的类, 为了更灵活, 我们应该使用的是 ...

  2. 23种设计模式之工厂方法(Factory Method Pattern)

    工厂方法 前面我们学习了简单工厂,发现一个问题就是简单工厂集合了矛盾,为了解决这个问题我们针对每一种产品提供一个工厂类.通过不同的工厂实例来创建不同的产品实例.在同一等级结构中,支持增加任意产品这种设 ...

  3. 设计模式---对象创建模式之工厂方法模式(Factory Method)

    前提:“对象创建”模式 通过“对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定.它是接口抽象之后的第一步工作. 典型模式(表现最为突出) 工 ...

  4. 设计模式学习之工厂方法(Factory Method,创建型模式)(2)

    接着上一讲中的简单工厂继续讲解,假如我们有了需要采集新的水果梨子,如果我们使用简单工厂中的方式的话,就会新增一个Pear类,然后实现Fruit类,然后修改FruitFactory类中获取实例的方法 g ...

  5. Java设计模式(2)——创建型模式之工厂方法模式(Factory Method)

    一.概述 上一节[简单工厂模式]介绍了通过工厂创建对象以及简单的利弊分析:这一节来看看工厂方法模式对类的创建 工厂方法模式: 工厂方法与简单工厂的不同,主要体现在简单工厂的缺点的改进: 工厂类不再负责 ...

  6. JAVA设计模式(01):创建型-工厂模式【工厂方法模式】(Factory Method)

    简单工厂模式尽管简单,但存在一个非常严重的问题.当系统中须要引入新产品时,因为静态工厂方法通过所传入參数的不同来创建不同的产品,这必然要改动工厂类的源码,将违背"开闭原则".怎样实 ...

  7. 工厂方法(Factory Method)模式

    一.工厂方法(Factory Method)模式 工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟的子类中. 工厂方法模式是简单工厂 ...

  8. 设计模式的征途—3.工厂方法(Factory Method)模式

    上一篇的简单工厂模式虽然简单,但是存在一个很严重的问题:当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背开闭原则.如何实现新增新产品而 ...

  9. 小菜学习设计模式(三)—工厂方法(Factory Method)模式

    前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...

  10. Java 工厂模式(一)— 工厂方法(Factory Method)模式

    一.工厂方法(Factory Method)模式: 1.什么是工厂方法模式? 工厂方法模式是类的创建型模式,又叫做虚拟构造子模式或者多态工厂模式.它的意义是创建产品对象的工厂接口,将实际创建工作推迟到 ...

随机推荐

  1. 在UWP应用中实现Gif播放

    众所周知,在UWP应用框架中,Image控件是无法播放GIF的图片,只能显示静态图,这样的体验不是特别友好.我在Win8.WP8.1的时候实现过gif播放功能,但是最近发现性能和播放效果都差强人意,大 ...

  2. jQuery easyui combobox级联及内容联想

    1.需求:已有一个下拉框A表示地区,现新增需求,需要在A选择不同地区时,增加一个展示该地区所有城市的下拉框B, 由于城市较多,要求B能实现用户输入和模糊匹配展示功能. 2.实现: (1)首先在A下面把 ...

  3. Android之线程回掉更新ui

    一:工作线程中的回掉更新UI public class MainActivity extends AppCompatActivity { private int i; private Callback ...

  4. 制作便携版 FireFox 火狐浏览器

    Firefox是一款可高度自定义的开源浏览器: 你可以访问 火狐DIY 定制自己的Firefox安装包, 此外,你还可以自己动手定制一款可以放在U盘随身携带的便携版Firefox火狐浏览器. 制作便携 ...

  5. 编写高质量JS代码的68个有效方法(七)

    [20141220]编写高质量JS代码的68个有效方法(七) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  6. [IR] Tolerant Retrieval & Spelling Correction & Language Model

    Dictionary不一定是个list,它可以是多种形式. 放弃Hash的原因: 通常,tree是比较适合的结构. From: http://www.cnblogs.com/v-July-v/arch ...

  7. [mysql]增加用户 授权 远程登录

    mysql创建用户和授权 1.创建用户: (注意:下面的指令,请在root用户下输入) CREATE USER "用户名" IDENTIFIED BY "密码" ...

  8. js中offsetLeft,offsetTop,offsetParent计算边距方法

    封装一个函数获得任一元素在页面的位置 var GetPosition= function (obj) { var left = 0; var top = 0; while(obj.offsetPare ...

  9. 利用session做国际化引起的old区内存爆满及修复方法

    题记:昨天加班打车回家,看见前面有辆路虎在高速上开的巨慢,挡住了我坐的出租车的路,于是就跟司机吐槽了一句:“前面这车怎么这么面啊?”,司机沉默了大概3秒,说了一句富含哲理性的话:“没有面车,只有面人” ...

  10. 如何花样展示自己的摄影作品?CSS+JS+Html

    注意:Windows平台推荐使用Edge.Chrome.FireFox,部分浏览器打不开 P.S.慢慢用鼠标在图片上拖拽会感觉更神奇     // 0.5 ? 1 : -1; }, ease: fun ...