Week_03 学习总结

用户头像
golangboy
关注
发布于: 2020 年 10 月 05 日

为什么要学设计模式?与软件架构师有什么关系?

现代大量软件是基于面向对象或者使用面向对象思想实现的。对象结构与关系的良好设计,都与设计模式有直接间接的关系。近几年,出现的各种编程语言,也只是在简化编程提升效率等方面进行改进,软件设计方面并未有大的突破。因此设计模式是必须精通,一方面用于工作实践;另一方面用于阅读各种开源代码。

设计模式有助于使软件结构清晰,逻辑关系简化明了,同时也使软件易于扩展,满足不断变化的需求。设计模式也不止用于代码层面的组织,也可用于架构层面的设计,典型场景下的配置管理,服务发现都是观察者模式或其变种。

但23种设计模式都是面对对象进行设计与组织,充分利用面向对象的继承,多态,封装等特点进行描述。缺少关于并发模型下的设计模式,对golang语言的新特性使用只有借鉴意义,不具备指导意义。

设计模式有哪些?

从功能进行划分,针对不同场景分为三大类:

  • 创建模式

  • 结构模式

  • 行为模式

以实现方式划分:

  • 对象继承模式(静态)

  • 对象组合模式(动态)

创建模式

  • 工厂模式

  • 抽象工厂模式

  • 生成器模式

  • 单例模式

  • 原型模式

结构模式

  • 适配器模式

  • 桥接模式

  • 组合模式

  • 装饰模式

  • 代理模式

  • 外观模式

行为模式

  • 职责链模式

  • 命令模式

  • 解释器模式

  • 迭代器模式

  • 中介者模式

  • 备忘录模式

  • 观察者模式

  • 状态模式

  • 策略模式

  • 模板模式

  • 访问者模式



一、抽象工厂模式

抽象工厂的目标是将抽象零件组装成抽象产品,不关心具体的实现。

现实问题

根据配置或者上下文的不同,动态的创建对象。减少程序中的硬编码,让程序有更多的灵活性

解决方案



具体效果

func main() {
user := &User{}
department := &Department{}
// 定义具体的工厂
factory := &MysqlFactory{}
// factory := &SqlServerFactory{}
// 下面的这些逻辑是一致的,不论要插入的数据库如何变化,这里都是不变的
// 决定这个工厂需要生产什么产品
iDepartment := factory.CreateDepartment()
iUser := factory.CreateUser()
iDepartment.Insert(department)
iUser.Insert(user)
}

关键之处:

  1. 用接口进行设计。

  2. 梳理客户端使用时的逻辑,对该逻辑进行抽象,定义抽象接口。

  3. 什么时候使用抽象工厂模式,取决于上述逻辑的抽象。

适用场景

  1. 抽象工厂模式存在的问题是,当需要增加新的产品时,需要修改抽象接口,修改所有具体工厂。(简单工厂模式可以应对产品的变化)

  2. 抽象工厂模式解决的问题是,可以灵活的增加具体工厂,而不用修改代码。

二、装饰器模式(decorator)

现实问题

对已有类进行功能扩展和增加时,用继承会产生大量子类,让结构变得复杂混乱。装饰器模式就是在原有类上进行包装,从而解决该问题

解决方案



具体效果

func main() {
xc := &Person{Name: "小菜"}
fmt.Println("第一种装扮")
pqx := &Sneakers{}
kk := &BigTrouser{}
dtx := &TShirts{}
pqx.Decorate(xc)
kk.Decorate(pqx)
dtx.Decorate(kk)
dtx.Show()
fmt.Println("第二种装扮")
px := &LeatherShoes{}
ld := &Tie{}
xz := &Suit{}
px.Decorate(xc)
ld.Decorate(px)
xz.Decorate(ld)
xz.Show()
}

关键之处:

  1. 装饰器模式相当于 a.show() -> b.show() -> c.show()

  2. 先定义装饰基类,再通过继承基类的方式进行定义具体装饰类,Decorate一样,Show不一样

适用场景

  1. 需要对原始类进行功能扩展,又不想定义子类继承让代码变复杂,装饰器模式在一定程度上降低了复杂性

  2. 过度使用装饰器模式,会导致有大量小的装饰对象产生,不好维护代码

三、外观模式(facade)

现实问题

客户端程序访问系统各个子系统,导致系统与客户程序耦合性增加,外观模式提供统一的访问接口,屏蔽子系统细节,解决该问题。

解决方案



具体效果

关键之处:

  1. facade的method中组织各个子系统的调用逻辑

  2. facade中有指向各子系统的索引

适用场景

四、中介者模式(mediator)

现实问题

对象间的通信,导致对象相互依赖。对对象的修改会影响很多其他对象,因为复杂的耦合关系导致代码难以维护。该模式为这种依赖关系解耦。

解决方案



具体效果

func main() {
m := &ConcreteMediator{}
c1 := &ConcreteColleague1{}
c1.Register(m)
c2 := &ConcreteColleague2{}
c2.Register(m)
m.Colleague1 = c1
m.Colleague2 = c2
c1.Send("吃饭了么?")
c2.Send("吃过了")
}

关键之处:

  1. 定义一个中间对象,通过中间对象,进行消息转发。

  2. mediator需要知道所有colleague

  3. colleague对象也需要知道mediator

  4. mediator相当于封装了colleague的通信过程

适用场景



五、观察者模式

现实问题

解决方案



具体效果

func main() {
s := &ConcreteSubject{}
s.Observers = make(map[Observer]struct{})
s.Attach(&ConcreteObserver{Name: "X", Subject: s})
s.Attach(&ConcreteObserver{Name: "Y", Subject: s})
s.Attach(&ConcreteObserver{Name: "Z", Subject: s})
s.SetState("ABC")
s.Notify()
}

关键之处:

  1. 观察者需要知道订阅的主题

  2. 主题通过attach将观察者进行登记

  3. 主题内容变更时,通知所有订阅该主题的观察者

  4. 主题与观察者是解耦的

  5. 主题(subject)和观察者(observer)一对接口,主题能接受并提醒观察者,观察者收到提醒后更新

适用场景

  • 设计的抽象模型有两个方面,一个依赖另一个,这是将这两者放到独立的对象中,使其独立的改变和复用。系统某些模块关心磁盘的状态,当磁盘状态改变时,通知相应的模块。

  • 一个对象的改变,同时触发其他对象的改变。典型应用场景前端react模型



六、访问者模式

现实问题

解决方案



具体效果

func main() {
// 要访问的对象
o := &ObjectStructure{
&ConcreteElementA{Name: "ConcreteElementA"},
&ConcreteElementB{Name: "ConcreteElementB"},
}
// 创建访问者,这些访问者有不同的处理方法
v1 := &ConcreteVisitor1{Name: "ConcreteVisitor1"}
v2 := &ConcreteVisitor2{Name: "ConcreteVisitor2"}
// 接受访问者处理
o.Accept(v1)
o.Accept(v2)
}

关键之处:

  1. 被访问对象的结构要稳定,访问的是这个对象里的某一些元素

  2. 元素访问到后,对其进行特殊的处理。将元素的处理逻辑,放到visitor中,以实现不同功能。通过这种方式解耦了被访问对象的关系,不会对原对象产生影响。

  3. 一个visitor接口,一个element接口是关键。具体的element接受的访问后,调用visitor相应处理函数

  4. visitor访问处理element是访问者模式的关键。

适用场景

  • 一个对象包含很多其他对象,用户想要对这些对象进行统一的处理。

  • 需要对对象中的对象进行很多不同且不相干的操作, 又不想污染这些对象

  • 对象接口稳定较少改变,但需要在此结构上定义新的操作。

七、状态模式

现实问题

解决方案

具体效果



适用场景

八、解释器模式

现实问题

解决方案

具体效果



适用场景

九、命令模式

现实问题

解决方案

具体效果



适用场景



十、备忘录模式

现实问题

解决方案

具体效果



适用场景

十一、代理模式

现实问题

解决方案

具体效果



适用场景



十二、迭代器模式

现实问题

解决方案

具体效果



适用场景



二、组合模式

现实问题

解决方案

具体效果



适用场景



  • 什么是组合模式



  • 使用场景是什么

需要对树状结构的逻辑或设计进行表达时,使用组合模式。

  • 注意事项

组合表征整体与部分的继承结构

允许客户端使用递归组合对单个对象和对象集合统一处理

用户头像

golangboy

关注

还未添加个人签名 2018.09.18 加入

还未添加个人简介

评论

发布
暂无评论
Week_03 学习总结