工厂模式根据条件产生不同功能类,工厂模式在解耦方面将使用者和产品之间的依赖推给了工厂,让工厂承担这种依赖关系。工厂模式分简单工厂模式、方法工厂模式和抽象工厂模式。Golang实现工厂模式,主要通过interface实现。实现方法也很简单,只要具体功能结构体实现对应工厂接口就可以了。以几个例子来看看golang中工厂模式的实现:
1、 简单工厂模式:
package main
import (
"fmt"
)
type Animal interface {
Saying()
}
type Cat struct {
}
type Programer struct {
}
type Factory struct {
}
func (c *Cat) Saying() {
fmt.Println("喵喵喵~~~")
}
func (p *Programer) Saying() {
fmt.Println("hello world")
}
func (f *Factory) CreateAnimal(name string) Animal {
switch name {
case "Cat":
return new(Cat)
case "Programer":
return new(Programer)
default:
panic("animal name not exist in the factory")
}
return nil
}
func main() {
var factory = new(Factory)
cat := factory.CreateAnimal("Cat")
cat.Saying()
programer := factory.CreateAnimal("Programer")
programer.Saying()
}
从代码可以看到,调用者无需知道具体的产品(Animal)构造产生的细节,只需要知道产品接口就可以了。这使得调用者(main函数)的代码相对逻辑比较单一,不用随产品的变化和做太大的调整(降低了调用者和产品之间的耦合),但是引入了和产品具有强耦合的类(工厂类)。在实际开发过程中根据具体情况看是否需要封装一个工厂类吧,如果有多个产品,且可以抽象出一个一致的接口,采用简单工厂方法模式可以让调用者的逻辑无须发生变化,在调用工厂类中创建具体产品类的时候做点小设置即可,这样就不用有多套代码了。
2、 工厂方法模式实现:
先来看看golang中方法工厂和抽象工厂模式的大致写法:
package main
import (
"fmt"
)
type Server interface {
GetServerType() string
}
type Factory interface {
CreateServer() Server
}
type RestfulFactory struct {
}
func (r *RestfulFactory) CreateServer() Server {
return &RestfulServer{}
}
type SoaFactory struct {
}
func (s *SoaFactory) CreateServer() Server {
return &SoaServer{}
}
type RestfulServer struct {
}
func (r *RestfulServer) GetServerType() string {
return "微服务"
}
type SoaServer struct {
}
func (s *SoaServer) GetServerType() string {
return "传统企业服务"
}
func main() {
var factory Factory
var server Server
factory = &RestfulFactory{}
server = factory.CreateServer()
fmt.Println("server type is: ", server.GetServerType())
//...
factory = &SoaFactory{}
server = factory.CreateServer()
fmt.Println("server type is: ", server.GetServerType())
}
其实工厂方法模式的实现就是将简单工厂方法中工厂类获取具体产品的方法再做一层抽象。减少了产品抽象和工厂之间的耦合关系,具体的工厂只和具体的产品有耦合关系。这样的话每次增加、减少产品的时候就不用修改工厂类获取具体产品的方法了,将产品的创建延迟到工厂子类中,但是这样也会产生多几个具体工厂类。
3、 抽象工厂模式
先来看看golang中方法工厂和抽象工厂模式的大致写法:
package main
import (
"fmt"
)
type Gatway interface {
CreateInputParser() Parser
CreeteOutPutEncoder() Encoder
}
type Parser interface {
ParseData()
}
type Encoder interface {
EncodeData()
}
type XmlParser struct {
}
func (x *XmlParser) ParseData() {
fmt.Println("parse xml data ok")
}
type JsonParser struct {
}
func (j *JsonParser) ParseData() {
fmt.Println("parse Json data ok")
}
type XmlEncoder struct {
}
func (x *XmlEncoder) EncodeData() {
fmt.Println("Encode xml data ok")
}
type JsonEncoder struct {
}
func (j *JsonEncoder) EncodeData() {
fmt.Println("Encode Json data ok")
}
type GatwayHuawei struct {
}
func (g *GatwayHuawei) CreateInputParser() Parser {
return &XmlParser{}
}
func (g *GatwayHuawei) CreeteOutPutEncoder() Encoder {
return &XmlEncoder{}
}
type GatwayTencent struct {
}
func (g *GatwayTencent) CreateInputParser() Parser {
return &JsonParser{}
}
func (g *GatwayTencent) CreeteOutPutEncoder() Encoder {
return &JsonEncoder{}
}
func main() {
var gatway Gatway
gatway = &GatwayHuawei{}
gatway.CreateInputParser().ParseData()
gatway.CreeteOutPutEncoder().EncodeData()
gatway = &GatwayTencent{}
gatway.CreateInputParser().ParseData()
gatway.CreeteOutPutEncoder().EncodeData()
return
}
从例子中可以看到,当一个功能需要多个接口的时候,可以优先考虑使用抽象工厂方法,抽象工厂模式可以看成两个或者多个工厂方法模式的组合。
总结:工厂模式总体上来看,可以分为简单工厂模式和工厂方法模式。当有几个产品,且产品比较固定的时候,使用简单工厂方法,在实现上来看,会比较的简单且逻辑比较的清晰。当产品比较多样化且可能会变化的时候,建议使用工厂方法模式和抽象工厂模式。