设计模式之工厂模式

工厂模式主要用来创建对象的

type Phone interface{
	Call()
}

type iPhone struct {

}

func (p * iPhone) Call() {
	fmt.Println("this is iphone calling")
}

type aPhone struct {

}

func (p * aPhone) Call() {
	fmt.Println("this is android phone calling")
}

type onePlusPhone struct {

}

func (p *onePlusPhone) Call() {
	fmt.Println("this is one plus phone calling")
}


// 简单的工厂模式,不符合开闭原则(拓展的时候要修改工厂“类”的源码)
func createPhone(name string) Phone {
	if name == "iPhone" {
		return &iPhone{}
	} else if name == "aPhone" {
		return &aPhone{}
	}
	return nil
}

上面代码是用golang实现的简单工厂模式,createPhone(工厂)里面用if分支创建各种“手机”(同一个接口),虽然是一个函数,和java版本里面的类静态方法是一个意思。

调用的测试代码页比较简单:

createPhone("iPhone").call()
createPhone("aPhone").call()

简单工厂模式不符合开闭原则(对拓展开放,对修改关闭)。当有一个sumPhone产品出现的时候,除了基本的产品结构定义,还要对createPhone工厂进行修改,(增加if分支)。

所以引出了抽象工厂模式

type Phone interface{
	Call()
}

type iPhone struct {

}

func (p * iPhone) Call() {
	fmt.Println("this is iphone calling")
}

type aPhone struct {

}

func (p * aPhone) Call() {
	fmt.Println("this is android phone calling")
}

type factory interface {
	CreatePhone() Phone
}

type iPhoneFactory struct {

}

func (mf * iPhoneFactory) CreatePhone() Phone{
	return &iPhone{}
}

type aPhoneFactory struct {

}

func (af * aPhoneFactory) CreatePhone() Phone{
	return &aPhone{}
}

抽象工厂模式,总体说就是把工厂也进行了抽闲,每一种产品都有对于的工厂实现类,(一一对应)的关系,符合开闭原则。

具体调用如下。


	var factory factory
	factory = &aPhoneFactory{}
	factory.CreatePhone().Call()

当有一个sumPhone产品出现的时候,需要创建sumPhone实现类(结构体),sumPnoneFactory实现类(结构体)就可以了,将创建对象的语句,延迟到了抽象工厂实现类的方法实现过程中。

抽象工厂对比简单工厂来说,类的数量和结构会比较多而复杂,理清楚关系就好理解了,同时符合开闭原则。

但是,仔细观察就会发现,虽然抽象工厂符合开闭原则,但是调用却出现了“硬编码”,即第二行的factory = &aPhoneFactory{},出现在调用代码中,如果要创建iPhone对象要写iPhoneFactory相关的语句…是不是在一定程度上把不符合开闭原则转移到这里了呢?而简单工厂模式在调用端是“软编码”,在一定程度上比较合理。

抽象工厂模式的“硬编码”可以通过反射来解决,在java中反射可以通过类名来创建对象,只要设置一些合理的存储类型如map等结构,结合本地配置文件,就可以实现调用端的软编码(不用写死具体的工厂实现类如aPhoneFactory{}),且整体都是符合开闭原则的。但是golang语言暂时不支持这一种方式的反射。而简单抽象工厂模式在服务端侧的违背开闭原则是不可避免的。