• 简单工厂模式 (Simple Factory Pattern)
  • 工厂方法模式 (Factory Method Pattern)

工厂模式: 工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。可分为简单工厂模式、工厂方法模式。以下分别对两种模式进行介绍。

简单工厂模式 (Simple Factory Pattern)

简单工厂模式,又称为静态工厂方法 (Static Factory Method) 模式,属于创建型模式,但不属于 23 种 GOF 设计模式之一。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,这个类就是工厂类,被创建的实例通常都具有共同的父类。下面用一个简单的计算器程序来介绍,计算器只包含加减乘除功能。

加减乘除四种操作类是运算类的子类,简单工厂类依赖于运算类。

运算类

package simple_factory;//运算类
public class Operation {private double num1;private double num2;public double getNum1() {return num1;}public void setNum1(double num1) {this.num1 = num1;}public double getNum2() {return num2;}public void setNum2(double num2) {this.num2 = num2;}//返回运算结果public double getResult() {return 0;}
}

加法类

package simple_factory;//加法类
public class Add extends Operation {@Overridepublic double getResult() {return this.getNum1() + this.getNum2();}
}

减法类

package simple_factory;//减法类
public class Sub extends Operation {@Overridepublic double getResult() {return this.getNum1() - this.getNum2();}
}

乘法类

package simple_factory;//乘法类
public class Mul extends Operation {@Overridepublic double getResult() {return this.getNum1() * this.getNum2();}
}

除法类

package simple_factory;//除法类
public class Div extends Operation {@Overridepublic double getResult() {return this.getNum1() / this.getNum2();}
}

工厂类

package simple_factory;//简单工厂类
public class OperationFactory {public static Operation createOperation(String op) {Operation operation = null;switch (op) {case "+":operation = new Add();break;case "-":operation = new Sub();break;case "*":operation = new Mul();break;case "/":operation = new Div();break;default:break;}return operation;}}

客户端

package simple_factory;//客户端
public class Client {public static void main(String[] args) {String op = "+";Operation operation = OperationFactory.createOperation(op);operation.setNum1(4);operation.setNum2(5);System.out.println(operation.getResult());;}
}

优点:

  • 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责
  • 客户端无需知道所创建具体产品的类名,只需知道具体产品类所对应的参数即可
  • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

缺点:

  • 工厂类集中了所有产品的创建逻辑,职责过重,一旦异常,整个系统将受影响
  • 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
  • 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
  • 简单工厂模式使用了static工厂方法,造成工厂角色无法形成基于继承的等级结构。

使用场景:

  • 工厂类负责创建的对象比较少,所以不会造成工厂方法中的业务逻辑过于复杂
  • 客户端只知道传入工厂类的参数,对如何创建对象不关心

总结: 简单工厂模式的优点在于工厂类中可以判断客户的的选择来动态实例化相关的类,对于客户端来说,去除了具体产品的依赖。但工厂类集中了对所有实例创建的逻辑,如果我们要新增子类或者改变方法的话,每次都得修改工厂类里面的代码,工厂类中的代码就会十分臃肿,这就等于说我们不仅开放了扩展,还开放了修改,这样就违反了 开放 - 封闭 原则。

工厂方法模式 (Factory Method Pattern)

工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。与简单工厂模式相比,其提供了一个抽象工厂角色来声明抽象工厂方法(抽象工厂可以是接口,也可以是抽象类或者具体类),而由其子类来具体实现工厂方法,创建具体的产品对象,不同的具体工厂可以创建不同的具体产品。

工厂方法模式组成:

  • 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
  • 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
  • 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
  • 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

实例

某系统运行日志记录器 (Logger) 可以通过多种途径保存系统的运行日志,例如通过文件记录或者数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。

  • Logger:日志记录器接口,充当抽象产品角色
package factory_method;//日志记录器接口,充当抽象产品角色
public interface Logger {public void writeLog();
}
  • DatabaseLogger :数据库日志记录器,充当具体产品角色
package factory_method;//数据库日志记录器,充当具体产品角色
public class DatabaseLogger implements Logger {@Overridepublic void writeLog() {System.out.println("数据库日志记录.");}
}
  • FileLogger:数据库日志记录器,充当具体产品角色
package factory_method;//文件日志记录器,充当具体产品角色
public class FileLogger implements Logger {@Overridepublic void writeLog() {System.out.println("文件日志记录。");}
}
  • LoggerFactory :日志记录器工厂方法,充当抽象工厂角色
package factory_method;//日志记录器工厂方法,充当抽象工厂角色
public interface LoggerFactory {public Logger createLogger();  //抽象工厂方法
}
  • DatabaseLoggerFactory :数据库日志记录器工厂类,充当具体工厂角色
package factory_method;//数据库日志记录器工厂类,充当具体工厂角色
public class DatabaseLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new DatabaseLogger();}
}
  • FileLoggerFactory :文件日志记录器工厂类,充当具体角色
package factory_method;//文件日志记录器工厂类,充当具体角色
public class FileLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new FileLogger();}
}
  • Client:客户端测试类
package factory_method;//客户端测试类
public class Client {public static void main(String[] args) {//可引入配置文件和反射机制实现LoggerFactory factory = new FileLoggerFactory();Logger logger = factory.createLogger();logger.writeLog();}
}

运行结果:

如果需要增加并使用新的日志记录器,只需要对应增加一个新的具体工厂类,然后再客户端代码中修改具体工厂类的类名,原有类库的源代码无需做任何修改。通过引入配置文件并使用反射机制可以实现在不修改客户端代码的基础上更换具体日志记录器。

优点

  • 更符合开-闭原则,新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。简单工厂模式需要修改工厂类的判断逻辑。
  • 符合单一职责原则,每个具体工厂类只负责创建对应的产品。简单工厂中的工厂类存在复杂的switch逻辑判断。
  • 不使用静态工厂方法,可以形成基于继承的等级结构。简单工厂模式的工厂类使用静态工厂方法。
  • 工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。

缺点

  • 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
  • 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
  • 一个具体工厂只能创建一种具体产品。

应用场景

  • 当一个类不知道它所需要的对象的类时 ,在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;
  • 当一个类希望通过其子类来指定创建对象时 ,在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

参考:
工厂模式–简单工厂模式
工厂方法模式(Factory Method)-最易懂的设计模式解析

工厂模式(简单工厂模式和工厂方法模式)详解相关推荐

  1. python硬件交互_对Python的交互模式和直接运行.py文件的区别详解

    对Python的交互模式和直接运行.py文件的区别详解 看到类似C:\>是在Windows提供的命令行模式,看到>>>是在Python交互式环境下. 在命令行模式下,可以执行p ...

  2. python 文件读写with open模式r,r+ w,w+ a,a+区别详解

    python 文件读写with open模式r,r+ w,w+ a,a+区别详解 python中的 with open主要要来进行文件读写的操作 在 Python 中使用文件的关键函数是 open() ...

  3. 计算机软故障无法开机,电脑常见的开机故障及解决方法的详解

    电脑常见的开机故障及解决方法的详解 发布时间:2012-11-07 14:12:47   作者:佚名   我要评论 造成电脑不能正常开机的情况有很多种,是没插插头?还是线缆松动?难道是机箱里面密密麻麻 ...

  4. python find的使用方法_Python中的rfind()方法使用详解

    Python中的rfind()方法使用详解 rfind()方法返回所在子str 被找到的最后一个索引,或者-1,如果没有这样的索引不存在,可选择限制搜索字符串string[beg:end]. 语法 以 ...

  5. linux系统密码输入快捷,linux 系统忘记密码的快捷解决方法(图文详解)

    linux 系统忘记密码的快捷解决方法(图文详解) 在学习Linux的过程当中,想到,万一自己忘记了linux的密码该怎么办? 其实,在linux当中,只用简单的操作几步,就可以更改用户密码~下面小编 ...

  6. unturned服务器配置文件,《Unturned》使用Bottle开3.0服务器方法图文详解

    <Unturned>使用Bottle开3.0服务器方法图文详解 2015-02-03 17:04:07来源:贴吧编辑:评论(0) <Unturned>游戏中玩家们可以联机作战, ...

  7. python怎么画条形图-python绘制条形图方法代码详解

    1.首先要绘制一个简单的条形图 import numpy as np import matplotlib.pyplot as plt from matplotlib import mlab from ...

  8. python装饰器函数-Python函数装饰器常见使用方法实例详解

    本文实例讲述了Python函数装饰器常见使用方法.分享给大家供大家参考,具体如下: 一.装饰器 首先,我们要了解到什么是开放封闭式原则? 软件一旦上线后,对修改源代码是封闭的,对功能的扩张是开放的,所 ...

  9. android+发邮件,Android发送邮件的方法实例详解

    Android发送邮件的方法实例详解 时间:2021-05-20 本文实例讲述了Android发送邮件的方法.分享给大家供大家参考,具体如下: 在android手机中实现发送邮件的功能也是不可缺少的. ...

  10. oracle大对象实例_Oracle解析复杂json的方法实例详解

    问题背景: 当前在Oracle数据库(11G之前的版本)解析json没有可以直接使用的系统方法,网上流传的PLSQL脚本大多也只可以解析结构较单一的json串,对于结构复杂的json串还无法解析.如此 ...

最新文章

  1. Java OOP(Object Oriented Programming)个人理解及总结
  2. zabbix3.0禁用guest用户
  3. 剑指offer 算法 (知识迁移能力2)
  4. Blackey win10 + python3.6 + VSCode + tensorflow-gpu + keras + cuda8 + cuDN6N环境配置(转载)
  5. mysql如何配置hbm.xml_配置数据库映射文件hbm.xml
  6. java二嗨租车项目_JAVA第二季项目实战———答答租车系统代码
  7. python如何下载os库_python下载os库的方法
  8. 美团外卖数据采集接口
  9. 162手写板合封芯片专用IC输出可达50V外围简单SOP8封装
  10. 躲在被窝里偷偷学爬虫(6)---处理cookie模拟登录及代理IP
  11. 无线路由当交换机的设置方法
  12. 使用JiaoZiVideoPlayer播放视频方向横过来出现的问题
  13. windows远程桌面登录不允许空密码
  14. python数据可视化案例 淘宝粽子_Python可视化对比分析淘宝低价人群和匿名用户的淘宝连衣裙数据...
  15. 任意波形发生器的设计
  16. 人工智能正在改变音乐产业
  17. 10个最受欢迎的JavaScript图表库
  18. mysql个人办公使用_Access数据库是给办公人员用的~闲杂人等不要来凑热闹
  19. Layui提示说明弹框
  20. Jenkins实现发送邮件

热门文章

  1. 腾讯云tca认证要具备哪些能力?腾讯云tca认证适合那些人群
  2. Flutter问题二:OBX数据嵌套重复更新
  3. Android开发实用小工具十三——BMI指数计算工具
  4. POI 设置Excel单元格背景色
  5. zigbee3.0@学习笔记@TI STACK@串口接收
  6. 《Linux/Unix设计思想:软件的杠杆效应》读后感
  7. 记我经历的一次公司破产经历,一行代码害死一家公司
  8. 制作可以滚动的卡片式界面
  9. 智能钢琴小提琴吉他教育曲谱识别(5线谱/6线谱)播放器源码 钢琴 吉他谱 智能钢琴
  10. 在PPT中如何制作光芒四射的背景