工厂方法模式(Factory Method Pattern)和建造者模式类似,都是将对象创建的逻辑封装起来,为使用者提供一个简单易用的对象创建接口,两者在应用场景上稍有区别,建造者模式常用于需要传递多个参数来进行实例化的场景;工厂方法模式常用于不指定对象具体类型的情况下创建对象的场景。

对于简单工厂来讲,一旦要增加新的产品就必须修改NewApi的逻辑,不符合开放关闭原则,因此进一步抽象工厂,将工厂定义为接口(工厂类),具体产品对应的工厂需实现这个接口

步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例

GO风格的工厂方法

对于工厂方法来讲,关键点在于客户端依赖工厂方法,而不是具体某个工厂,可以抽象一个工厂接口,当然也可以使客户端直接依赖工厂方法(函数一等公民)
利用函数一等公民的特性以及闭包来实现,能够少定义几个接口和结构体,使代码更简洁

  1. // 关键点1: 定义Sidecar工厂方法类型(返回某个接口)
  2. type FactoryFunc func() network.Socket
  3. // 关键点2: 按需定义具体的工厂方法实现,注意这里定义的是工厂方法的工厂方法,返回的是FactoryFunc工厂方法类型,而不是具体的接口,否则无法实现多态
  4. func RawSocketFactoryFunc() FactoryFunc {
  5. return func() network.Socket {
  6. return network.DefaultSocket()
  7. }
  8. }
  9. func AllInOneFactoryFunc(producer mq.Producible) FactoryFunc {
  10. return func() network.Socket {
  11. return NewAccessLogSidecar(NewFlowCtrlSidecar(network.DefaultSocket()), producer)
  12. }
  13. }
  14. type ServiceMediator struct {
  15. ...
  16. server *http.Server
  17. // 关键点3: 客户端依赖FactoryFunc工厂方法类型(注意不是直接依赖接口),并在此结构体初始化时注入具体的工厂方法
  18. sidecarFactoryFunc FactoryFunc
  19. }
  20. //使用时:
  21. func (s *ServiceMediator) Forward(req *http.Request) *http.Response {
  22. ...
  23. dest, err := s.discovery(svcType)
  24. // 关键点4: 创建HTTP客户端,调用sidecarFactoryFunc()生成Socket作为入参
  25. client, err := http.NewClient(s.sidecarFactoryFunc(), s.localIp)
  26. resp, err := client.Send(dest, forwardReq)
  27. ...
  28. }
  29. // 关键点5: 在ServiceMediator初始化时,将具体类型的FactoryFunc注入到ServiceMediator中
  30. mediator := &ServiceMediator{
  31. sidecarFactoryFunc: RawSocketFactoryFunc()
  32. // sidecarFactory: AllInOneFactoryFunc(producer)
  33. }

典型场景

  1. 对象实例化逻辑较为复杂时,可选择使用工厂方法模式/简单工厂/静态工厂方法来进行封装,为客户端提供一个易用的接口。
  2. 如果实例化的对象/接口涉及多种实现,可以使用工厂方法模式实现多态。
  3. 普通对象的创建,推荐使用静态工厂方法(在go中就是最简单的用函数初始化实例,如NewXXX),比直接的实例化(比如 &Packet{src: src, dest: dest, payload: payload})具备更好的可读性和低耦合。

工厂方法模式能够与客户端解耦,当实例化逻辑变更时,只需要变更对应的工厂方法即可,不需要变更客户端代码。
注意将工厂方法模式与抽象工厂模式区分,抽象工厂模式主要运用在实例化“产品族”的场景,可以看成是工厂方法模式的一种演进。

简单工厂

工厂方法的另一个变种就是简单工厂,他不依赖于多态来实现,在go中直接用普通函数配合switch等判断语句来生产实例化后的对象

  1. // 关键点1: 定义sidecar类型
  2. type Type uint8
  3. // 关键点2: 按照需要定义sidecar具体类型
  4. const (
  5. Raw Type = iota
  6. AllInOne
  7. )
  8. // 关键点3: 定义简单工厂对象
  9. type SimpleFactory struct {
  10. producer mq.Producible
  11. }
  12. // 关键点4: 定义工厂方法,入参为sidecar类型,根据switch-case或者if-else来创建产品
  13. func (s SimpleFactory) Create(sidecarType Type) network.Socket {
  14. switch sidecarType {
  15. case Raw:
  16. return network.DefaultSocket()
  17. case AllInOne:
  18. return NewAccessLogSidecar(NewFlowCtrlSidecar(network.DefaultSocket()), s.producer)
  19. default:
  20. return nil
  21. }
  22. }
  23. // 关键点5: 创建产品时传入具体的sidecar类型,比如sidecar.AllInOne
  24. simpleFactory := &sidecar.SimpleFactory{producer: producer}
  25. sidecar := simpleFactory.Create(sidecar.AllInOne)