创建型 工厂模式

为什么需要工厂模式

一般来说工厂模式下面还有更加细分的类型,简单工厂、工厂方法和抽象工厂。

一般来说工厂模式最主要的作用就是根据输入变量或者配置文件,解析以后根据情况返回不同类型的对象实例。

那我们一般情况下什么时候需要工厂模式呢?

  1. 创建过程可能会有变更,封装逻辑,使变更对使用者透明
  2. 允许代码复用,抽象化创建过程
  3. 封装复杂的创建逻辑

简单工厂

一般来说根据输入参数选择好类型,返回对象就好。根据open closure原则,还是勉强符合的。在需要增添一个类的时候,就是需要继承Gun这个父类,实现创建过程,然后在NewGun里面注册一下即可使用。

go.mod

module factory

go 1.13

factory/simplefactory/simplefactory.go

package simplefactory

type IGun interface {
	Fire() string
}

type Gun struct {
	name string
}

func NewGun(name string) IGun {
	if name == "ak47" {
		return newAk47()
	}

	if name == "maverick" {
		return newMaverick()
	}

	return nil
}

func (g *Gun) Fire() string {
	return g.name + " Fire"
}

type ak47 struct {
	Gun
}

func newAk47() IGun {
	return &ak47{
		Gun: Gun{
			name: "ak47",
		},
	}
}

type maverick struct {
	Gun
}

func newMaverick() IGun {
	return &maverick{
		Gun: Gun{
			name: "maverick",
		},
	}
}

factory/simplefactory/simplefactory_test.go

package simplefactory_test

import (
	"factory/simplefactory"
	"testing"
)

func TestSimpleFactory(t *testing.T) {
	ak47 := simplefactory.NewGun("ak47")
	maverick := simplefactory.NewGun("maverick")
	if ak47.Fire() != "ak47 Fire" {
		t.Fatal("Incorrect ak47")
	}

	if maverick.Fire() != "maverick Fire" {
		t.Fatal("Incorrect maverick")
	}
}

执行: go test factory/simplefactory -v

工厂方法模式

这个主要是去掉一个集中的创建方法,把创建factory的过程交还给各个具体实现的类。扩展性更加高一点。当用户要增加新的Gun的时候只需要增加:

  1. 具体Gun 类
  2. 具体GunFactory 类
  3. 在init 函数那里去具体注册

使用场景,需要得到factory创建过程并且做一些复杂的创建配置的时候,可以考虑采用这个设计模型。

factory/factorymethod/factorymethod.go

package factorymethod

type IGun interface {
	Fire() string
}

// IGunFactory abstracts out Gun creator. 这个是主要区别
type IGunFactory interface {
	NewGun() IGun
}

var cacheFactories map[string]IGunFactory

func init() {
	cacheFactories = make(map[string]IGunFactory)
	cacheFactories["ak47"] = &ak47Factory{}
	cacheFactories["maverick"] = &maverickFactory{}
}

func NewGunFactory(name string) IGunFactory {
	return cacheFactories[name]
}

type Gun struct {
	name string
}

// we don't need NewGun anymore

func (g *Gun) Fire() string {
	return g.name + " Fire"
}

type ak47 struct {
	Gun
}

type ak47Factory struct {
}

func (af *ak47Factory) NewGun() IGun {
	return &ak47{
		Gun: Gun{
			name: "ak47",
		},
	}
}

type maverick struct {
	Gun
}

type maverickFactory struct{}

func (mf *maverickFactory) NewGun() IGun {
	return &maverick{
		Gun: Gun{
			name: "maverick",
		},
	}
}

factory/factorymethod/factorymethod_test.go

package factorymethod_test

import (
	"factory/factorymethod"
	"testing"
)

func TestFactoryMethod(t *testing.T) {
	ak47Factory := factorymethod.NewGunFactory("ak47")
	maverickFactory := factorymethod.NewGunFactory("maverick")
	ak47 := ak47Factory.NewGun()
	maverick := maverickFactory.NewGun()

	if ak47.Fire() != "ak47 Fire" {
		t.Fatal("Incorrect ak47")
	}

	if maverick.Fire() != "maverick Fire" {
		t.Fatal("Incorrect maverick")
	}
}

执行: go test factory/factorymethod -v

Previous
Next