GOLANG工厂模式、简单工厂模式、抽象工厂模式、创建者模式

      设计模式可以大大提高代码复用性,使得程序的修改更加灵活。另外将各个功能模块抽象解耦出来,在某个模块需要更改时不至于会对整体代码进行修改,解耦的好的话只简单修改几个地方即可以切换某个模块在实现上的切换,这就提高了程序修改的灵活度,以便应对客户各种各样的需求。

       大话设计模式第一章就通过写一个计算器(计算逻辑和前端显示解耦)和曹操饮酒改诗(每修改或者增加一个字就需要全部重新刻录,并且就的刻版只能作废)例子说明了设计模式的重要性。同时展示了简单工厂模式,简单工厂模式整体的思路是在一个创建函数中,通过switch case语句分别创建不同的实例,但是这些实例都有一些共同的属性,比如加减运算中,在创建一个加法类时,这个类有两个数字和一个返回结果的函数,减法也差不多一样只是返回函数不一样而已。这样我们就可以用简单工厂方法来生成加法类、减法类、乘法类等等。GO的实例代码如下:

//这个interface用来保存大致一样的类
type API interface {
	Say(name string) string
}

//这个是工厂函数,返回一个interface
func NewAPI(t int) API  {
	if t == 1 {
		return &hiAPI{}
	} else if t == 2 {
		return &helloAPI{}
	}

	return nil
}

//这个是一个具体的类型,hi
type hiAPI struct{}
func (*hiAPI)Say(name string) string {
	return fmt.Sprintf("Hi, %s", name)
}
//这是一个具体的类型,hai
type helloAPI struct {
}
func (*helloAPI)Say(name string) string  {
	return fmt.Sprintf("Hello, %s", name)
}

客户端代码:
func TestType1(t *testing.T)  {
	api := NewAPI(1)
	s := api.Say("Tom")
	if s != "Hi, Tom" {
		t.Fatal("Type1 test failed")
	}
}

        简单工厂模式在增加一个新的类型时,除了要增加新的类和方法之外,还需要修改工厂函数,在工厂函数中添加case,这一点违背了对修改关闭这个原则(开放-封闭原则),所以需要工厂模式。

工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。看一下代码你就知道了

package factoryCreate

type Operator interface {
	SetA(int)
	SetB(int)
	Result() int
}

//定义一个用于创建对象的接口
//实际中是这个interface在各个函数中传来传去,当需要实例化一个类的时候,调用Create方法
//具体的加减函数中,使用这个interface的Create方法返回的Operator interface做各种加减
type OperatorFactory interface {
	Create() Operator
}

type OperatorBase struct {
	a, b int
}
//set A
func (o *OperatorBase) SetA(a int) {
	o.a = a
}
//SetB
func (o *OperatorBase) SetB(b int) {
	o.b = b
}

//这里还创建一个新的加法工厂类,这个依赖于下面的具体加法类
type PlusOperatorFactory struct {
}
//这个类实现了这个方法之后,不但可以让这个类的实例赋值给OperatorFactory
//还可以通过这个函数创建加法实际操作的实例-PlusOperator类型的实例
func (PlusOperatorFactory) Create() Operator {
	return &PlusOperator{
		OperatorBase: &OperatorBase{},
	}
}
//具体的加法类
type PlusOperator struct {
	*OperatorBase
}
func (o PlusOperator) Result() int {
	return o.a + o.b
}

//减法工厂类,依赖于下面的具体减法类
type MinusOperatorFactory struct{}
func (MinusOperatorFactory) Create() Operator {
	return &MinusOperator{
		OperatorBase: &OperatorBase{},
	}
}
//具体的减法类
type MinusOperator struct {
	*OperatorBase
}
func (o MinusOperator) Result() int {
	return o.a - o.b
}

//**************************客户端代码:
func compute(factory OperatorFactory, a, b int) int {
	op := factory.Create()
	op.SetA(a) //这里类似于虚函数调用实际的子类函数。。。
	op.SetB(b)

	return op.Result()
}

func TestOperator(t *testing.T) {
	var (
		factory OperatorFactory //类似于基类
	)

	factory = PlusOperatorFactory{} //类似于一个子类
	if compute(factory, 1, 2) != 3 {
		t.Error("error with factory method pattern")
	}

	factory = MinusOperatorFactory{} //另一个子类
	if compute(factory, 4, 2) != 2 {
		t.Fatal("error with factory method pattern")
	}
}

 工厂函数在增加一个新的类型的时候,像上面的例子里,只要增加一个新类型的工厂类,里面实现

Create() Operator方法,同时增加具体类型type MinusOperator struct {  *OperatorBase} 就好了。这里的OperatorBase是一个技巧。没有违背开放-封闭原则。我们注意在客户端中computer函数中我们可以做到不管你是加法还是减法,我们都调用了名字“一样”的函数,运算与类的产生已经有所解耦了。但是假如,上面的例子中,我们不仅仅要产生Operator方法,我们还要给第一个数上黄色,第二个数上绿色,如果我们在Operator中添加方法的话,显然需要改动的地方就太多了,我们应该是添加一个新的interface,里面有setAColor(),setBColor()方法,在客户端我们拿到这个新的interface,然后调用setAColor()比较可取。这个功能就需要用到抽象工厂模式了

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

package abstractfactory

import "fmt"

type OrderMainDAO interface {
	SaveOrderMain()
}

type OrderDetailDAO interface {
	SaveOrderDetail()
}
//这是一个接口,这个接口会创建一系列相互依赖(RDBDAOFactory和XMLDAOFactory 依赖于 OrderMainDAO)、
// 或者相互相关(OrderMainDAO和OrderDetailDAO相关)的对象,
//在客户端中创建RDBDAOFactory和XMLDAOFactory时,并不需要指定这两个类型
type DAOFactory interface {
	CreateOrderMainDAO() OrderMainDAO
	CreateOrderDetailDAO() OrderDetailDAO
}

type RDBMainDAO struct {
}
func (*RDBMainDAO) SaveOrderMain() {
	fmt.Print("rdb main save\n")
}

type RDBDetailDAO struct {
}
func (*RDBDetailDAO) SaveOrderDetail() {
	fmt.Sprint("rdb detail save\n")
}

type RDBDAOFactory struct {
}
func (*RDBDAOFactory) CreateOrderMainDAO() OrderMainDAO {
	return &RDBMainDAO{}
}
func (*RDBDAOFactory) CreateOrderDetailDAO() OrderDetailDAO {
	return &RDBDetailDAO{}
}

//**********************

type XMLMainDAO struct {
}
func (*XMLMainDAO) SaveOrderMain() {
	fmt.Sprint("xml main save\n")
}

type XMLDetailDAO struct {
}
func (*XMLDetailDAO) SaveOrderDetail() {
	fmt.Print("xml datail save")
}

type XMLDAOFactory struct {
}
func (*XMLDAOFactory) CreateOrderMainDAO() OrderMainDAO {
	return &XMLMainDAO{}
}
func (*XMLDAOFactory) CreateOrderDetailDAO() OrderDetailDAO {
	return &XMLDetailDAO{}
}

 

客户端代码

func getMainAndDetail(factory DAOFactory) {
	factory.CreateOrderMainDAO().SaveOrderMain()
	factory.CreateOrderDetailDAO().SaveOrderDetail()
}

func TestRdbFactory(t *testing.T) {
	var factory DAOFactory
	factory = &RDBDAOFactory{}
	getMainAndDetail(factory)
}

func TestXmlFactory(t *testing.T) {
	var facotry DAOFactory
	facotry = &XMLDAOFactory{}
	getMainAndDetail(facotry)
}

这里如果我们要在添加新的操作,也就是在DAOFactory这个interface中添加新的操作,我们需要改的地方就比较多。我们可以用简单工厂来封装一下,然后在简单工厂函数中用反射来自动判断需要创建那种类型,这是比较高级的玩法,留作练习。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值