这次介绍的设计模式是工厂模式,这是一个比较常见的创建型模式。一般情况下,工厂模式分为三种:简单工厂、工厂方法和抽象工厂,下面慢慢举例介绍下。
简单工厂考虑一个加密程序的应用场景,一个加密程序可能提供了AES,DES等加密方法,这些加密方式都实现了同一个接口ICipher,它有两个方法分别是 Encript 和 Decript。我们使用加密程序的时候会希望简单的指定加密方式,然后传入原始数据以及必要参数,然后就能得到想要的加密数据。这个功能用简单工厂如何实现呢?
模式结构简单工厂模式包含一下几个角色:
Factory(工厂角色),负责创建所有实例。
Product(抽象产品角色),指工厂所创建的实例的基类,在 golang 中通常为接口。
ConcreteProduce(具体产品),指工厂所创建的具体实例的类型。
在这个加密程序的例子中,工厂角色的职责是返回加密函数;抽象产品角色是所有加密类的基类,在 golang 中是定义了加密类通用方法的接口;具体产品是指具体的加密类,如 AES、DES 等等。我们可以用 UML 关系图来表示这几个角色之间的关系:
代码设计依据 UML 关系图,我们可以设计出采用简单工厂模式的加密代码。首先是 ICipher 接口,定义了 Encript 和 Decript 两个方法:
type ICipher interface { Encrypt([]byte) ([]byte, error) Decrypt([]byte) ([]byte, error) }然后根据这个接口,分别实现 AESCipher 和 DESCipher 两个加密类。
AESCipher:
type AESCipher struct { } func NewAESCipher() *AESCipher { return &AESCipher{} } func (c AESCipher) Encrypt(data []byte) ([]byte, error) { return nil, nil } func (c AESCipher) Decrypt(data []byte) ([]byte, error) { return nil, nil }DESCipher:
type DESCipher struct { } func NewDesCipher() *DESCipher { return &DESCipher{} } func (c DESCipher) Encrypt(data []byte) ([]byte, error) { return nil, nil } func (c DESCipher) Decrypt(data []byte) ([]byte, error) { return nil, nil }最后是一个工厂角色,根据传入的参数返回对应的加密类,Java 需要实现一个工厂类,这里我们用一个函数来做加密类工厂:
func CipherFactory(cType string) ICipher { switch cType { case "AES": return NewAESCipher() case "DES": return NewDesCipher() default: return nil } }这样,通过调用 CipherFactory 传入所需的加密类型,就可以得到所需要的加密类实例了。
func TestCipherFactory(t *testing.T) { c := CipherFactory("RSA") if c != nil { t.Fatalf("unsupport RSA") } c = CipherFactory("AES") if reflect.TypeOf(c) != reflect.TypeOf(&AESCipher{}) { t.Fatalf("cipher type should be AES") } c = CipherFactory("DES") if reflect.TypeOf(c) != reflect.TypeOf(&DESCipher{}) { t.Fatalf("cipher type should be DES") } } 小结简单工厂将业务代码和创建实例的代码分离,使职责更加单一。不过,它将所有创建实例的代码都放到了 CipherFactory 中,当加密类增加的时候会增加工厂函数的复杂度,产品类型增加时需要更新工厂函数这一操作也是违反了“开闭原则”,所以简单工厂更适合负责创建的对象比较少的场景。
工厂方法为了让代码更加符合“开闭原则”,我们可以给每个产品都增加一个工厂子类,每个子类生成具体的产品实例,将工厂方法化,也就是现在要介绍的工厂方法模式。
模式结构工厂方法和和简单工厂相比,将工厂角色细分成抽象工厂和具体工厂:
Product(抽象产品):定义产品的接口。
ConcreteFactory(具体产品):具体的产品实例。
Factory(抽象工厂):定义工厂的接口。
ConcreteFactory(具体工厂):实现抽象工厂,生产具体产品。
可以使用如下的 UML 图来表示这几个角色直接的关系:
抽象产品角色和具体产品角色就不再定义了,和简单工厂相同,具体展示一下抽象工厂角色和具体工厂角色。
抽象工厂角色定义了一个方法,用于创建对应的产品:
根据这个接口,分别定义出 AESCipherFactory、和 DESCipherFactory 两个子类工厂。
AESCipherFactory
type AESCipherFactory struct { } func (AESCipherFactory) GetCipher() ICipher { return NewAESCipher() } func NewAESCipherFactory() *AESCipherFactory { return &AESCipherFactory{} }DESCipherFactory
type DESCipherFactory struct { } func (DESCipherFactory) GetCipher() ICipher { return NewDESCipher() } func NewDESCipherFactory() *DESCipherFactory { return &DESCipherFactory{} }