最近在看《大话设计模式》,这本书通过对话形式讲解设计模式的使用场景,有兴趣的可以去看一下。

第一篇讲的是简单工厂模式,要求输入两个数和运算符号,得到运行结果。

这个需求不难,难就难在类要怎么设计,才能达到可复用、维护性强、可拓展和灵活性高。

运算符可能是加、减、乘、除,未了方便以后可以拓展其它运算符,这里可以声明一个抽象接口,通过简单工厂设计模式返回不通的运算类。

package operate

type IOperate interface {
    GetResult(a int, b int) int
}

首先声明一个IOperate抽象接口表示运算,然后新建AddSubMulDiv结构体实现这个运行接口:

package operate

type Add struct{}

func (o Add) GetResult(a int, b int) int {
    return a + b
}

type Sub struct{}

func (o Sub) GetResult(a int, b int) int {
    return a - b
}

type Mul struct{}

func (o Mul) GetResult(a int, b int) int {
    return a * b
}

type Div struct{}

func (o Div) GetResult(a int, b int) int {
    if b == 0 {
        panic("除数不能为0")
    }
    return a / b
}

然后定义一个工厂,参数为运算符号:

package main

// NewOperate 按照操作符号创建操作对象
func NewOperate(o string) operate.IOperate {
    switch o {
    case "+":
        return operate.Add{}
    case "-":
        return operate.Sub{}
    case "*":
        return operate.Mul{}
    case "/":
        return operate.Div{}
    default:
        panic("操作符号错误")
    }
}

最后运行:

package main

import "fmt"

func main() {
    var a, b int
    fmt.Println("请输入两个数:")
    fmt.Scanf("%d %d", &a, &b)
    fmt.Println("请输入运算符号(+、-、*、/):")
    var operate string
    fmt.Scanf("%s", &operate)
    operateObj := NewOperate(operate)
    result := operateObj.GetResult(a, b)
    fmt.Printf("%d %s %d = %d\n", a, operate, b, result)
}

要增加不同的运算操作只需要新增实现了抽象运算接口的结构体和修改工厂,因为go语言的函数也是一种类型,其实上面的代码可以简化,不用每次都新增一个结构体:

type OperateFun func(a, b int) int

// GetOperateFunc 按照操作符号创建操作函数,函数式编程
func GetOperateFunc(o string) OperateFun {
    switch o {
    case "+":
        return func(a, b int) int {
            return a + b
        }
    case "-":
        return func(a, b int) int {
            return a - b
        }
    case "*":
        return func(a, b int) int {
            return a * b
        }
    case "/":
        return func(a, b int) int {
            if b == 0 {
                panic("除数不能为0")
            }
            return a / b
        }
    default:
        panic("操作符号错误")
    }

main函数可以这样调用:

var a, b int
fmt.Println("请输入两个数:")
fmt.Scanf("%d %d", &a, &b)
fmt.Println("请输入运算符号(+、-、*、/):")
var operate string
fmt.Scanf("%s", &operate)
operateFun := GetOperateFunc(operate)
result = operateFun(a, b)
fmt.Printf("%d %s %d = %d\n", a, operate, b, result)

写业务代码还是要多想一下用什么设计模式合适,避免编写的代码后面不好维护和扩展,这需要多练习。