简单工厂模式
目录
定义
提供一个创建对象实例的功能,而无需关心其具体的实现,被创建的对象类型可以是接口、抽象类、也可以是具体的类。
我们在平时使用接口的时候常常会有如下场景:
//定义一个接口
package main
import "fmt"
type IPerson interface {
GetUserName(str string)
}
type user struct {
}
func (u *user) GetUserName(str string) {
fmt.Println("My Blog Name:",str)
}
func main() {
var u user
u.GetUserName("blog.68hub.com")
}
以上列子中,客户端不仅知道了接口,同时还知道了具体的实现类user
。接口的思想是封装隔离,而实现类user
应该是被
接口IPerson
封装并同客户端隔离开的(客户端根本就不应该知道具体的实现类是user
)
用来解决上述问题的一个合理方案就是简单工厂。
虽然不能让模块外部知道模块内部的具体实现,但是模块内部是可以知道实现类的,而且创建接口是需要具体实现类的。
那么干脆在模块内部新建一个类,在这个类里面来创建接口,然后吧创建好的接口返回给客户端,这样外部应用只需要根据这个类来获取相应的接口对象,然后就可以操作接口定义的方法了。把这样的对象称为简单工厂Factory
。
客户端就可以通过Factory
来获取需要的接口对象,然后调用接口的方法来实现需要的功能,而且客户端不需要关心具体的实现了。
示例代码
具体代码实现如下:
package main
import "fmt"
type IPerson interface {
GetName(str string)
}
type User struct {}
func (u *User) GetName(str string) {
fmt.Println("Hello ",str)
}
// Golang 中没有构造方法,可以使用一个函数来实现
func NewFactory() IPerson {
return &User{}
}
func main() {
NewFactory().GetName()
}
虽然说简单工厂的方法大多是用来创建接口的,但是仔细分析就会发现,真正能实现功能的是具体的实现类,这些实现类是已经做好的,并不是真的要靠简单工厂来创造出来的。简单工厂的方法其实就是:实现了选择一个合适的实现类来使用。
选择合适的实现类,来创建实例对象。
那么就需要选择的条件或者选择的参数,具体代码如下:
package main
import "fmt"
type IPerson interface {
GetName(str string)
}
type User struct{}
func (u *User) GetName(str string) {
fmt.Println("User ", str)
}
type Student struct{}
func (s *Student) GetName(str string) {
fmt.Println("Student ", str)
}
func NewFactory(i int) IPerson {
if i == 1 {
return &User{}
} else if i == 2 {
return &Student{}
}
return nil
}
func main() {
NewFactory(1).GetName("hello")
NewFactory(2).GetName("world")
}
简单工厂优缺点:
优点
-
帮助封装
简单工厂虽然简单,但是非常友好地帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。
-
解耦
通过简单工厂,实现了客户端和具体实现类的解耦。
缺点
-
可能增加客户端的复杂度
如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这样会增加的客户端使用的难度,也暴露了内部实现,这种情况可以选用可配置的方式来实现。
-
不方便扩展子工厂
私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。
合适选用简单工厂(建议)
如果想要把创建对象的职责集中管理和控制,可以选用简单工厂,一个简单工厂可以创建很多不相关的对象,可以把对外创建对象的职责集中到一个简单工厂来,从而实现集中管理和控制。
总结
简单工厂的本质是:选择实现
其重点在选择。**实现**是已经做好了的。就算实现再简单,也要由具体的实现类来实现,而不是在简单工厂里面来实现。简单工厂的目的在于为了客户端来选择相应的实现,从而使得客户端和实现之间解耦。
实现简单工厂的难点就在于__“如何选择”__实现,可以是静态参数,可以实现成为动态的参数,比如在运行期间,由工厂方法读取某个内存的值,或者是去读取数据库中的值,然后根据这个值来选择具体的实现。
参考
研磨设计模式-简单工厂