本文不限于任何面向对象的编程语言
常常听别人说设计模式不太容易理解,以及学习设计模式到底能帮我们解决什么问题,今天我们就用几张图来看看:
是的,没什么,我也写过烂代码,刚毕业时业务逻辑也会一个函数干到底,只知道能实现功能就可以了。
package demo
func YourFunc() {
// 所有的逻辑代码一股脑写完......
}
自然而然知道了需要合理拆分函数。
然后把各个函数组织起来。
某一天产品的需求需要支持新的场景,发现某一处的代码逻辑有变动需要支持新的场景,怎么办?
上面这种解决问题的方式就是面向过程的编程思想。
随着我们不断的学习,学会使用了面向对象的特性。
以往函数式编程:
package demo
// 函数式编程
// 把一个个你以为可以独立的逻辑封住到一个函数里
func YourFunc() {
// ......
}
面向对象编程:
package demo
// 面向对象编程
// 把不同的逻辑独立成一个对象
type DemoStruct struct{}
func (d *DemoStruct) YourFunc() {
// ......
}
所以,我们如何用面向对象的思想组织上面的代码呢?
答案:继承。
特别备注:Go里面用合成复用
定义一个父类,并把差异业务代码抽象为一个抽象函数,其他代码逻辑都实现在父类。
不同的场景定义为不同的子类,子类继承父类,并实现抽象方法(也就是写差异代码)。
灰色:父类
绿色:场景一子类
蓝色:场景二子类
是不是很优雅的解决上面的场景的问题。
优雅的解决上面场景问题时,利用面向对象特性的经验总结,就是设计模式。然而在历史的长河中,已经为我们总结了20+的常用设计模式,我们只需要学习和加以灵活运用即可。比如:
还记得上面使用继承的过程吗?其实我们只需要做一件事情,就是经典的模板模式了,是什么?
答案:保证该场景下父类中封装的方法调用过程是稳定不变的,只是其中的方法可能变化。
灰色:父类
绿色:场景一子类
蓝色:场景二子类
黄色:场景三子类
我们把上面代码做些改动:
package demo
// DemoInterface 接口
type DemoInterface interface {
DoSomething(ctx *Context) error
}
var CurrentStrategyInstance DemoInterface
func Demo() {
//.....逻辑略......
CurrentStrategyInstance.DoSomething(c)
//.....逻辑略......
}
灰色:主业务类
灰色:主业务类
绿色:场景一DemoInterface的具体实现类
灰色:主业务类
绿色:场景一DemoInterface的具体实现类
蓝色:场景二DemoInterface的具体实现类
灰色:主业务类
绿色:场景一DemoInterface的具体实现类
蓝色:场景二DemoInterface的具体实现类
黄色:场景三DemoInterface的具体实现类
接着我们把判断不同的场景初始化不同的具体类单独封装起来,这就是简单工厂模式 + 策略模式。
package demo
type DemoFactory struct {
}
// Get 获取实例
func (f *DemoFactory) Get(instanceType string) DemoInterface {
switch instanceType {
case "DemoA":
return &DemoA{}
case "DemoB":
return &DemoB{}
case "DemoC":
return &DemoC{}
default:
panic("不支持的类型")
}
}
// DemoInterface 接口
type DemoInterface interface {
DoSomething(ctx *Context) error
}
var CurrentStrategyInstance DemoInterface
func Demo() {
//.....逻辑略......
CurrentStrategyInstance = (DemoFactory{}).Get("DemoA")
CurrentStrategyInstance.DoSomething(c)
//.....逻辑略......
}
灰色(大):主业务类
灰色(小):简单工厂类
绿色:场景一DemoInterface的具体实现类
蓝色:场景二DemoInterface的具体实现类
黄色:场景三DemoInterface的具体实现类
假设判断上面使用何种策略不是依赖外部,而是依赖内部状态,则我们调整下代码,则就变成了状态模式。
package demo
var currentStateInstance DemoInterface
func init() {
// 定时器更新状态
go func() {
for {
select {
case t := <-time.NewTicker(1 * time.Second).C:
// 模拟变成状态 StateA
currentStateInstance = setState("StateA")
}
}
}()
}
// Get 获取实例
func setState(State string) DemoInterface {
// 变更状态
switch State {
case "StateA":
return &StateA{}
case "StateB":
return &StateB{}
case "StateC":
return &StateC{}
default:
panic("不支持的状态")
}
}
// DemoInterface 接口
type DemoInterface interface {
DoSomething(ctx *Context) error
}
// type StateA StateB StateC 略
// 模拟
func Demo() {
//.....逻辑略......
CurrentStateInstance.DoSomething(c)
//.....逻辑略......
}
灰色(大):主业务类
灰色(小):修改内部状态的函数
绿色:场景一DemoInterface的具体实现类
蓝色:场景二DemoInterface的具体实现类
黄色:场景三DemoInterface的具体实现类
举了这么多?,所以关于:
你有答案了吗?