深入设计模式04---工厂方法模式
前言
公司这一阵时间忙过去了,有了几天的空闲时间,近期想要学习下SpringCloud(分布式框架),通过之前下载的一个某培训机构的学习项目来学习,今天简单的跟着文档把框架搭起来了。不得不说,这培训机构的老师还是很有东西的,单看架构这一方面就让人觉得很优雅,让我的心中也不由得小小的震撼了一把,各种设计模式在项目中用的是手到擒来,系统搭建的非常具有扩展性,这样的代码看起来简直就像是艺术品一样,值得让人细细的体会了解。优秀的编码风格以及深切贴合面向对象思想的代码在我们看来是非常舒服的,希望大家写代码可以注意简单优雅,不要生产出垃圾代码,这样早晚有一天我们也能够达到老师的水准。(项目git地址)
好了,进入正题,工厂方法模式是简单工厂模式的延申,他继承了简单工厂模式的优点,弥补了简单工厂模式的缺点,更好的符合开闭原则,在新增加具体产品对象时不需要对已有的代码进行任何修改。
正文
概述
定义一个用于创建对象的接口,但是让子类决定是哪一个类被实例化。工厂方法模式让一个类的实例化延申到其子类。
工厂方法模式的设计思想如下:
我们在简单工厂模式中如果想要新增一个产品类就需要修改工厂类中的创建对象的方法,这并不符合开闭原则,而在工厂方法模式中,我们将生产对象的方法提取出来作为一个抽象的类或接口,然后让具体的工厂实现类来实现该方法产生对象,打个比方也就是工厂A生产A产品,工厂B生产B产品,如果我们现在需要新增一个C产品,那么也只需要在新增一个工厂C实现生产对象的接口即可,不需要对已有的带谬进行修改,这很好的符合了开闭原则。
工厂方法模式被直接称为工厂模式,又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。真正产生对象的是抽象工厂类的子类。结构与实现
模式结构
- Factory(抽象工厂类): 抽象工厂类中声明一个方法,用于返回产品,具体工厂类实现该方法返回产品对象。
- ConcreteFactory(具体工厂类): 实现了抽象工厂类中产生对象的方法,生产对象,客户端真正调用的是此方法来产生对象。
- Product(抽象产品角色): 产品的抽象定义,所有产品对象的公共父类。
- ConcreteProduct(具体产品类): 实现了抽象产品类,每一种具体产品类都对应一个具体工厂类,该具体工厂类负责生产该具体产品类。
实现Demo
与简单工厂模式不同的是工厂方法模式引入了抽象工厂角色。
目录结构:
简单而典型且优雅的抽象产品类代码:public abstract class Product {public abstract void sayHello();}
具体产品类: 具体产品类中实现抽象产品类中定义的抽象方法来做具体的业务逻辑操作。
public class ProductA extends Product {@Overridepublic void sayHello() {System.out.println("A say hello");} }
public class ProductB extends Product {@Overridepublic void sayHello() {System.out.println("B say hello");} }
抽象工厂类: 抽象工厂类可以是接口,也可以是抽象类或者具体类。
public interface Factory {Product getProduct();}
具体工厂类: 具体工厂类继承或实现抽象工厂类,与具体产品类一一对应,负责生产产品,在具体环境中,具体工厂类一般还要负责对象一些复杂的初始化过程。
public class ProductAFactory implements Factory {@Overridepublic Product getProduct() {System.out.println("产生了产品类A");return new ProductA();} }
public class ProductBFactory implements Factory {@Overridepublic Product getProduct() {System.out.println("产生了产品类B");return new ProductB();} }
客户类: 模拟消费产品类
public class Client {/*** 模拟客户类* @param args*/public static void main(String[] args) {Factory factory = new ProductAFactory(); // 可以通过配置文件与反射实现factory.getProduct().sayHello();Factory factory1 = new ProductBFactory(); // 可以通过配置文件与反射实现factory1.getProduct().sayHello();} }
可以通过配置文件来配置具体的工厂类,然后通过反射机制创建具体的工厂类,从而使在更换具体的工厂时无需修改代码,只需要修改配置文件。
超真实案例
需求: 现有一个日志记录器,要求可以通过多种途径保存日志,如: 通过文件记录\通过数据库记录,日志记录器需要一些初始化工作,且这些初始化参数的设置过程较为复杂,而且某些参数设置有严格的现后顺序,否则可能发生记录失败,为了更好的封装记录器的初始化过程;
结构: 首先需要将记录日志的方法提取出来作为接口( 抽象产品类Product ),各种日志记录方式实现该接口的记录日志方法( 具体产品ConcreteProduc t),一个可以生产各种不同记录日志的工厂接口(抽象工厂类Factory),具体生产对象的类(具体工厂类ConcreteFactory)。
客户端通过修改配置文件修改存储日志的方式上代码
public interface Logger {void writeLog(); }
具体的实现类: 需要实现抽象产品类中的方法(真实环境中需要巨多的业务逻辑以及属性,由于我们是学习环境,搞得太复杂了不好理解,这里简化下)
public class FileLogger implements Logger {@Overridepublic void writeLog() {System.out.println("日志记录到了文件");}}
public class DatabaseLogger implements Logger {@Overridepublic void writeLog() {System.out.println("日志记录到了数据库");}}
public class ConsoleLogger implements Logger {@Overridepublic void writeLog() {System.out.println("日志输出到了控制台");}}
public interface LoggerFactory {// 创建日志记录器的方法,在实现类中可以通过重载来创建出属性不同的LoggerLogger createLogger();}
具体工厂类: 实现了抽象工厂类,负责创建以及初始化Logger类,与Logger类一一对应
public class FileLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {System.out.println("经过了非常复杂的创建过程创建出了FileLogger!");Logger logger = new FileLogger();return logger;} }
public class DatabaseLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {System.out.println("经过了非常复杂的创建过程创建出了DatabaseLogger!");Logger logger = new DatabaseLogger();return logger;} }
public class ConsoleLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {System.out.println("经过了非常复杂的创建过程创建出了ConsoleLogger!");Logger logger = new ConsoleLogger();return logger;} }
config配置文件: 配置了具体的工厂类,代码中通过解析该配置文件获取具体工厂类的类名,然后通过反射获取具体工厂对象;
<?xml version="1.0" ?> <config><className>com.xz.example.factory.impl.ConsoleLoggerFactory</className> </config>
public class XMLUtil {public static Object getBean(){try {// 创建DOM文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = dFactory.newDocumentBuilder();Document doc = documentBuilder.parse(new File("FactoryMethodPattern/src/com/xz/example/config.xml"));// 获取配置beanNodeList nl = doc.getElementsByTagName("className");Node node = nl.item(0).getFirstChild();String clazzName = node.getNodeValue();// 利用反射生成对象并返回Object obj = Class.forName(clazzName).newInstance();return obj;} catch (Exception e) {e.printStackTrace();return null;}}}
public class Client {/*** 模拟客户类* 需求:* 现有一个日志记录器,要求可以通过多种途径保存日志,如: 通过文件记录\通过数据库记录,日志记录器需要一些初始化工作,* 且这些初始化参数的设置过程较为复杂,而且某些参数设置有严格的现后顺序,否则可能发生记录失败,为了更好的封装记录器的初始化过程* 并保证多种记录器切换的灵活性,要求使用工厂方法模式设计改系统,常见的日志记录工具有SLF4J,Log4j等.* <p>* 分析:* 首先需要将记录日志的方法提取出来作为接口(抽象产品类Product),各种日志记录方式实现该接口的记录日志方法(具体产品ConcreteProduct),* 一个可以生产各种不同记录日志的工厂接口(抽象工厂类Factory),具体生产对象的类(具体工厂类ConcreteFactory).** @param args*/public static void main(String[] args) {Object bean = XMLUtil.getBean();if (bean != null && bean instanceof LoggerFactory){LoggerFactory loggerFactory = (LoggerFactory) bean;Logger logger = loggerFactory.createLogger();logger.writeLog();}}}
工厂方法的隐藏:
有时候为了进一步的简化 客户端的使用,我们可以将创建对象的方法向客户端隐藏,直接在工厂中提供一个方法实现对具体产品的调用,从而实现业务操作。public abstract class LoggerFactory {public void writeLog(){Logger logger = this.createLogger();logger.writeLog();}// 创建日志记录器的方法,在实现类中可以通过重载来创建出属性不同的Loggerpublic abstract Logger createLogger();}
优缺点分析
优点
- 工厂方法用来创建客户所需要的产品,并且向客户隐藏了哪种具体产品类被实例化,用户只需要关心生产产品的工厂,甚至不需要知道产品的类名。
- 抽象工厂与抽象产品类使工厂方法模式更加具有多态性。
- 系统在加入新的产品时无需修改已有的代码,只需增加一个具体产品类以及对应的具体工厂类即可,客户端的代码也无需修改,只需要修改配置文件即可。
缺点
- 在增加新的产品类时必须要新增一个具体的工厂类,这样导致扩展时类的个数是成对增加的。增加了系统的复杂度,会有更多的类需要被编译和运行,给系统带来额外的开销;
- 为了考虑系统的可扩展性,引入了抽象层,在客户端中均使用抽象层进行定义,增加了系统的抽象性和理解难度。
适用环境
在以下情况下可以考虑使用工厂方法模式:
1. 客户端不知道他所需要的对象的类,只需要知道对应的工厂即可;
2. 抽象工厂类通过其子类来指定创建哪个对象,其自身只需要提供一个抽象的创建对象的方法,让子类实现,这利用了面向对象的多态性和里氏转换原则。
自练习习题
自律即自由!!!
半原创博客,用以记录学习,希望可以帮到您,不喜可喷。
深入设计模式04---工厂方法模式相关推荐
- python类是实例的工厂_Python设计模式之工厂方法模式实例详解
本文实例讲述了Python设计模式之工厂方法模式.分享给大家供大家参考,具体如下: 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪一个类, ...
- 设计模式复习-工厂方法模式
设计模式复习-工厂方法模式 相对于简单工厂,工厂方法是把算法类的实例化延迟到了调用者那去做,调用者根据自己的需要,自己实例化相关的工厂并且生产相关算法.这么做是因为简单工厂是不满足OCP的,因为如果 ...
- C#设计模式(3)——工厂方法模式
一.引言 在简单工厂模式中讲到简单工厂模式的缺点,有一点是--简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样就会造成简单工厂的实现逻辑过于复杂,然而本专题介绍的工厂方法模式可以 ...
- 设计模式之工厂方法模式(创建型)
一.模式定义 工厂方法模式:又称工厂模式,也叫虚拟构造器模式,属于构建型设计模式,工厂方法模式是在简单工厂模式上进行拓展,生产产品的过程由具体工厂类实现,基类只实现接口,这使得工厂方法模式可以在不修改 ...
- 设计模式之工厂方法模式应用例题
设计模式之工厂方法模式应用例题 题目描述 类结构图及相关说明 程序代码 运行结果 题目描述 现需要设计一个程序来读取多种不同类型的图片格式,针对每一种图片格式都设计一个图片读取器(ImageReade ...
- 设计模式:工厂方法模式(Factory method)
设计模式:工厂方法模式(Factory method) 一.问题 在前一章中通过披萨的实例介绍了简单工厂模式.在披萨实例中,如果我想根据地域的不同生产出不同口味的披萨,如纽约口味披萨,芝加哥口味披萨. ...
- 【设计模式】工厂方法模式(C#)
[设计模式]工厂方法模式 1.概述 针对简单工厂中的缺点,使用工厂方法模式就可以完美的解决,完全遵循开闭原则. 定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象.工厂方法使一个产品类的实例化 ...
- 一文叫你弄懂Java设计模式之工厂方法模式:图解+日志记录器代码实例
文章目录 详解Java设计模式之工厂方法模式 案例引入工厂方法模式 工厂方法模式 定义 案例分析 UML类图分析 代码分析 工厂方法的重载 工厂方法的隐藏 模式优点 模式缺点 模式适用环境 详解Jav ...
- 设计模式之工厂方法模式、抽象工厂模式的概念和实现及使用“反射技术+读取配置文件”的方法对工厂模式进行改进(软件工程综合实践课程第三周个人作业)
文章目录 一.实验目的 二.知识总结 1.工厂方法模式简介 2.抽象工厂模式简介 3.工厂模式小结 4.利用"反射技术+读取配置文件"的方法改进程序 三.实验内容 1. 工厂模式实 ...
- 设计模式之工厂方法模式(Factory Method)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.FactoryMethod(工厂方法模式):2.Abstract Factory(抽象工厂模式):3.Sin ...
最新文章
- ORB_SLAM2中Tracking线程
- Blender从头到尾创建一个低多边形场景学习教程
- IDApython 命令
- python编码解码的过程_使用Python过程中的编码和解码
- 【爬虫】beautiful soup笔记(待填坑)
- react html编辑器,react项目中使用富文本编辑器
- window.event.srcElement在Firefox IE下的兼容问题
- c# Linq Where 抛出异常 导致 程序崩溃
- Animoca Brands 旗下子公司 GAMEE 将于 4 月 2 日启动公募
- 解决IE9下JQuery的ajax失效的问题
- [转载] 计算机端口详解
- 人大金仓数据库迁移工具
- nRF52840 SAADC单通道/多通道采集分析
- 计算机组成原理——常用计算单位的转换(时间单位换算s、ms、μs;K、M、G为单位的数值大小)
- 《信息化项目文档模板十——系统用户操作手册模板》
- ylbtech-dbs:ylbtech-4,PurpleHouse(房地产楼盘销售系统)
- chm文档打开后提示已取消网页导航
- Ubuntu18.04 安装NVIDIA英伟达驱动教程
- 汇编指令:使用汇编指令计算2的8次方
- 1. Pycharm新建项目