Skip to content

设计模式-工厂方法

目录

总结

(本文尽可能的不参考深入设计模式所给出的案例或者描述, 部分内容插入自身的理解)

应对部分对象可能有着共同的方法, 但需要不同实现的设计模式.

或者换个角度讲, 某些对象仅仅在部分方法上存在不同的操作, 而可以通用很多基础操作, 因此构建一个工厂, 将共同方法放置在工厂中, 随后各自实现各自不同的操作。

但是需要注意的是, 工厂中的对象对外暴露的内容应该是一致的, 只是自己的操作不同而已。

最早写工厂的时候, 是在 Spring 里面, 所以一直在想为什么工厂还需要自己处理选择哪个具体实现, 然后才反应过: 那个是依赖注入, 和工厂方法是两个东西。

问题

丑团外卖最开始只支持丑团骑手配送, 但是由于部分商家具有一定特殊性(例如位于校内, 或需要配送特殊地点)。 导致丑团骑手并不能进行配送, 因此用户无法得知自己的外卖当前进度如何, 于是丑团决定支持其他配送平台。

但是当前代码应该如何修改呢? 绝大部分配送代码都与丑团骑手相关, 而且配送平台可能并不只一家, 要支持茫茫多的配送骑手也是一个非常困难的事情。

方案

工厂方法将创建对象的方法封装在自己的工厂内部, 每个配送平台都可以根据工厂暴露的接口来实现自己的配送逻辑, 当商家选择配送时, 只需要输入对应的配送平台名称, 工厂就可以根据配送平台的名称来匹配对应的配送平台, 然后返回配送信息。

应用场景

当你在编写代码的过程中, 如果无法预知对象确切类别及其依赖关系时, 可使用工厂方法。

在进行面向对象抽象的时候, 比较常见的一个情况是, 我们可以得知父对象, 而不知道子对象的具体类型。 因此在进行部分操作的时候可能需要频繁的进行类型转换。

因此我们可以将具体的方法封装到父对象内部, 或者构建一个专门的工厂, 由工厂来处理类型转换, 对外部就是不可见的了, 可以将频繁的类型转换隐藏于工厂内部, 简化对外的调用。

如果你希望用户能扩展你软件库或框架的内部组件, 可使用工厂方法。

这个比较常见在框架开发中, 框架提供的能力不能完全的符合用户需求, 因此需要考虑用户如何可以方便的进行二次开发以便于自身, 考虑使用工厂方法。

具体的操作就是将现有的不同子类型和建立的步骤集成到工厂中, 允许用户去重写这个工厂方法或者重写工厂中的某一个步骤方法。

在 Spring 构建三级缓存的过程中, BeanProcessor 涉及到 Bean 创建前、中、后三个部分, 当用户需要参与到具体的 Bean 处理的时候(比如处理自己新增的注解以对部分 Bean 进行监控管理), 就是在修改工厂中的处理流程。

如果你希望复用现有对象来节省系统资源, 而不是每次都重新创建对象, 可使用工厂方法。

这个解释起来比较简单, 对于需要重复利用的大量资源, 连接池、线程池等, 构建一个统一的工厂进行对象的创建\销毁\存储等管理。

伪代码

class Animal{
  private String type = "Animal";
  private void woo();
  public void to_woo(){
    self.woo();
  }
}

class Cat extends Animal{
  private String type = "Cat";
  private void woo(){
    System.out.println("miao miao miao");
  }
}

class Dog extends Animal{
  private String type = "Dog";
  private void woo(){
    System.out.println("wang wang wang");
  }
}
// 将创建的东西交给工厂方法, 对外只需要知道 Animal 可以 woo 即可。
public Animal CreateAnimal(String type = "Cat"){
  if(type.equals("Cat")){
    return new Cat();
  }
  else if(type.equals("Dog")){
    return new Dog();
  }
}


class Main(){

  public static void main(String[] args){
    Animal a = new CreateAnimal();
    a.to_woo();
  }
}

优缺点

优点:

  • 单一职责, 所有的对象被统一管理到了一个位置
  • 开闭原则, 无需更改现有代码即可加入新的类型
  • 解耦合, 分离应用者与具体类型之间的联系 缺点:
  • 子类较多的时候可能导致工厂代码复杂, 难以维护

异同

TODO: 等待学习其他模式后进行补充