文章目录
前言
什么时候不用
由于对象的创建过程被高效的抽象在一个接口后面的事实,这也会给依赖于这个过程可能会有多复杂的单元测试带来问题。
介绍
工厂模式的流程
+------------------+
| Client |
+------------------+
|
| requests
V
+------------------+
| Factory |
+------------------+
|
| selects
V
+---------------------+
| Concrete Factory |
+---------------------+
|
| creates
V
+---------------------+
| Concrete Product |
+---------------------+
|
| returns
V
+------------------+
| Client |
+------------------+
- 客户端(Client)向工厂对象发出请求。
- 工厂对象(Factory)根据客户端的请求选择合适的具体工厂。
- 具体工厂(Concrete Factory)创建所需的具体产品(Concrete Product)对象。
- 工厂将创建的对象返回给客户端。
例子
class Product {
constructor(name) {
this.name = name
}
init() {
console.log('init')
}
fun() {
console.log('fun')
}
}
class Factory {
create(name) {
return new Product(name)
}
}
// use
let factory = new Factory()
let p = factory.create('p1')
p.init()
p.fun()
场景
- 如果你不想让某个子系统与较大的那个对象之间形成强耦合,而是想运行时从许多子系统中进行挑选的话,那么工厂模式是一个理想的选择
- 将new操作简单封装,遇到new的时候就应该考虑是否用工厂模式;
- 需要依赖具体环境创建不同实例,这些实例都有相同的行为,这时候我们可以使用工厂模式,简化实现的过程,同时也可以减少每种对象所需的代码量,有利于消除对象间的耦合,提供更大的灵活性
优点
- 创建对象的过程可能很复杂,但我们只需要关心创建结果。
- 构造函数和创建者分离, 符合“开闭原则”
- 一个调用者想创建一个对象,只要知道其名称就可以了。
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
缺陷
增加了类的数量引入工厂模式会增加代码的复杂度,因为需要定义接口、具体工厂和具体产品等额外的类,从而增加了类的数量。
不易于扩展如果需要添加新的产品类型,就需要修改工厂类的逻辑,这违反了开闭原则(对扩展开放,对修改关闭)。
难以理解对于简单的项目,引入工厂模式可能会增加不必要的复杂性,使代码难以理解。
静态工厂方法不易被继承如果使用静态工厂方法来创建对象,则无法通过继承改变所创建的产品类型。
增加了代码的抽象程度工厂模式引入了额外的抽象层,使得代码更加抽象,可能增加理解和调试的难度。