工厂方法模式(Factory Method Pattern)和建造者模式类似,都是将对象创建的逻辑封装起来,为使用者提供一个简单易用的对象创建接口,两者在应用场景上稍有区别,建造者模式常用于需要传递多个参数来进行实例化的场景;工厂方法模式常用于不指定对象具体类型的情况下创建对象的场景。
对于简单工厂来讲,一旦要增加新的产品就必须修改NewApi的逻辑,不符合开放关闭原则,因此进一步抽象工厂,将工厂定义为接口(工厂类),具体产品对应的工厂需实现这个接口
步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
GO风格的工厂方法
对于工厂方法来讲,关键点在于客户端依赖工厂方法,而不是具体某个工厂,可以抽象一个工厂接口,当然也可以使客户端直接依赖工厂方法(函数一等公民)
利用函数一等公民的特性以及闭包来实现,能够少定义几个接口和结构体,使代码更简洁
// 关键点1: 定义Sidecar工厂方法类型(返回某个接口)type FactoryFunc func() network.Socket// 关键点2: 按需定义具体的工厂方法实现,注意这里定义的是工厂方法的工厂方法,返回的是FactoryFunc工厂方法类型,而不是具体的接口,否则无法实现多态func RawSocketFactoryFunc() FactoryFunc {return func() network.Socket {return network.DefaultSocket()}}func AllInOneFactoryFunc(producer mq.Producible) FactoryFunc {return func() network.Socket {return NewAccessLogSidecar(NewFlowCtrlSidecar(network.DefaultSocket()), producer)}}type ServiceMediator struct {...server *http.Server// 关键点3: 客户端依赖FactoryFunc工厂方法类型(注意不是直接依赖接口),并在此结构体初始化时注入具体的工厂方法sidecarFactoryFunc FactoryFunc}//使用时:func (s *ServiceMediator) Forward(req *http.Request) *http.Response {...dest, err := s.discovery(svcType)// 关键点4: 创建HTTP客户端,调用sidecarFactoryFunc()生成Socket作为入参client, err := http.NewClient(s.sidecarFactoryFunc(), s.localIp)resp, err := client.Send(dest, forwardReq)...}// 关键点5: 在ServiceMediator初始化时,将具体类型的FactoryFunc注入到ServiceMediator中mediator := &ServiceMediator{sidecarFactoryFunc: RawSocketFactoryFunc()// sidecarFactory: AllInOneFactoryFunc(producer)}
典型场景
- 对象实例化逻辑较为复杂时,可选择使用工厂方法模式/简单工厂/静态工厂方法来进行封装,为客户端提供一个易用的接口。
- 如果实例化的对象/接口涉及多种实现,可以使用工厂方法模式实现多态。
- 普通对象的创建,推荐使用静态工厂方法(在go中就是最简单的用函数初始化实例,如NewXXX),比直接的实例化(比如 &Packet{src: src, dest: dest, payload: payload})具备更好的可读性和低耦合。
工厂方法模式能够与客户端解耦,当实例化逻辑变更时,只需要变更对应的工厂方法即可,不需要变更客户端代码。
注意将工厂方法模式与抽象工厂模式区分,抽象工厂模式主要运用在实例化“产品族”的场景,可以看成是工厂方法模式的一种演进。
简单工厂
工厂方法的另一个变种就是简单工厂,他不依赖于多态来实现,在go中直接用普通函数配合switch等判断语句来生产实例化后的对象
// 关键点1: 定义sidecar类型type Type uint8// 关键点2: 按照需要定义sidecar具体类型const (Raw Type = iotaAllInOne)// 关键点3: 定义简单工厂对象type SimpleFactory struct {producer mq.Producible}// 关键点4: 定义工厂方法,入参为sidecar类型,根据switch-case或者if-else来创建产品func (s SimpleFactory) Create(sidecarType Type) network.Socket {switch sidecarType {case Raw:return network.DefaultSocket()case AllInOne:return NewAccessLogSidecar(NewFlowCtrlSidecar(network.DefaultSocket()), s.producer)default:return nil}}// 关键点5: 创建产品时传入具体的sidecar类型,比如sidecar.AllInOnesimpleFactory := &sidecar.SimpleFactory{producer: producer}sidecar := simpleFactory.Create(sidecar.AllInOne)
