工厂方法模式

83 阅读3分钟

image.png

工厂方法模式是面向对象开发一个很常见的模式,定义是这样的

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

优点:扩展性好,客户端只需要知道产品抽象类而不需要知道具体的产品类,降低了客户端与具体产品类的耦合。

缺点:类的个数可能会过多,增加了系统的复杂度。

“客户”只需通知工厂自己要什么“产品”;工厂负责创建“产品”,工厂方法中创建哪些“产品”会延迟到子类或者静态方法中,工厂是保持不变的。

你真的需要吗

工厂方法模式能帮我们解决下面几个问题:

  1. 使用和创建耦合

我们在使用A的地方如果需要创建A,当我们新增B的时候那么需要在使用的地方也新增B的创建,可扩展性差。在工厂模式中使用和创建是分离的。

  1. 创建混乱

创建A可能有一套逻辑,创建B又有一套逻辑,他们依赖的参数或者环境不同。而工厂方法模式中的工厂可以提供统一创建的逻辑,工厂和使用分离开了,而且工厂一旦“建好”也不需要再修改了,只需要维护静态方法或者子类。

xflow

xflow中的命令管理模块使用了工厂方法模式,但也不是严格定义上的工厂方法模式,实例化的过程没有延迟到子类或者静态方法,而是就在工厂内部。

xflow中存在着大量的命令,例如节点添加、删除等,边的移动、添加等,图相关的命令等,如果每次新增命令都修改“客户代码”哪可扩展性太差了。

  1. 注册“产品”

“产品”这里指的是命令,比如节点添加命令。

hookhubList.forEach(({ command }) => { registry.registerCommand(command, { createCommand: this.commandFactory, }) })

hookhubList中包括节点、边、图等的命令类,“command”指的是这个命令的标示,所以这里就是把所有的命令标示和this.commandFactory关联了起来。

无论那个命令都需要通过commandFactory获取。

hookhubList是通过入口文件收集的各个命令,入口文件很简单,就是导入、导出。

import { NsAddNode, AddNodeCommand } from './node-add' export const hookhubList: { command: IGraphCommand hookKey: string createHook?: () => HookHub }[] = [ NsAddNode, ]

所以如果新增了一个命令,难么只用维护这个入口文件就可以了。

  1. 获取“产品”

通过命令标示来获取命令对象,不能直接得到命令对象,而要先得到工厂-commandFactory,commandFactory就是工厂模式中手的工厂,调用commandFactory需要传入命令ID,commandFactory会创建响应的上下文环境,然后返回ID对应的命令对象。

项目中如何使用

其实react中高阶组件或者自定义hooks就类似工厂方法模式,比“产品”组件通过高级组件包括一层,这部分是“产品”组件决定的,然后高阶组件把创建好的“产品”组件返给上层组件,高阶组件内部会有“产品”组件和数据的处理逻辑。