铺垫
设计原则
- 针对接口编程,而不是针对实现编程
- 优先使用对象组合(黑箱),而不是类继承(白箱)
需要重新设计的原因
- 通过显示地指定一个类来创建对象
- 对特殊操作的依赖
- 对硬件和软件平台的依赖
- 对对象表示或实现的依赖
- 算法依赖
- 紧耦合 - 屎山(
- 通过生成子类来拓充功能
- 不能方便地对类进行修改
怎样重新选择设计模式
- 考虑设计模式是怎么样解决设计问题的
- 浏览模式的意图部分 - 1.4
- 研究模式怎么互相关联
- 研究目的相似的模式
- 检查重新设计的原因 - 为什么写成了屎山(
- 考虑你的设计中哪些是可变的

如何使用设计模式
- 大致浏览一遍 - 关注其适用性部分和效果部分
- 研究结构部分、参与者部分和协作部分 - 弄清楚这个模式的类和对象以及他们的关联关系
- 看示例代码 - dddd
- 在类名中加入参与者的名字 - 比如
SimpleLayoutStrategy
中的Strategy
就是一种设计模式
- 定义类,定义模式中专用于应用的操作名称 - 通过统一的命名来标注这是一个设计模式
- 实行执行模式中责任和协作的操作 - 明确每个模式中的单一职责,明确模块之间通过接口进行交互协作,减少模块间的互相依赖,松耦合,拒绝屎山(
组合模式 (Composite Pattern)
特点
- WYSIWYG的排版布局中,一个类既可以包含父类又可以作为父类使用
- 可以方便地访问一个类的父类和子类,并且接口通用
解释
e.g. 
在图中Row既是Glyph的子类,同时也可以存储Glyph类型,做到类似于类的递归,方便管理
策略模式(Strategy Pattern)
特点
- 可以根据不同的类选择不同的算法函数进行操作,充分利用多态
举例
这里拿golang来举例,顺便解释一下里面的一些语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package main
import ( "fmt" "sort" )
type SortStrategy interface { Sort([]string) []string }
type AlphabeticalSort struct{}
func (a AlphabeticalSort) Sort(data []string) []string { sort.Strings(data) return data }
type LengthSort struct{}
func (l LengthSort) Sort(data []string) []string { sort.SliceStable(data, func(i, j int) bool { return len(data[i]) < len(data[j]) }) return data }
type TextProcessor struct { strategy SortStrategy }
func (t *TextProcessor) SetStrategy(strategy SortStrategy) { t.strategy = strategy }
func (t *TextProcessor) SortText(data []string) []string { return t.strategy.Sort(data) }
func main() { data := []string{"apple", "banana", "kiwi", "cherry"}
processor := TextProcessor{strategy: AlphabeticalSort{}} fmt.Println("按字母顺序排序:", processor.SortText(data))
processor.SetStrategy(LengthSort{}) fmt.Println("按长度排序:", processor.SortText(data)) }
|
这里面func (a AlphabeticalSort) Sort(data []string) []string
的a AlphabeticalSort
代表Sort
方法属于"类"AlphabeticalSort
,需要在该类内使用,所以有了t.strategy.Sort(data)
。同理,你可以往这个struct里面加一些变量,在函数中就可以读取,相当于一个配置文件了。
注意,不能为基础类型进行接口实现,需要自定义一个类型,不过这个类型可以等于基础类型,比如type MyString string
,这样就可以变相地在string
类型上做接口了,虽然好像并没有什么卵用
用处
- 在完成具体操作不同但是类型和工作流相同的任务的时候可以使用该策略进行分流操作
装饰器模式 (Decorator Pattern)
特点
- 可以从基类装饰器中拓展出更多操作方式,使得项目具有强大的拓展性
举例
还在go,但是里面有一些新用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package main
import ( "fmt" )
type Text interface { Render() string }
type SimpleText struct{}
func (s *SimpleText) Render() string { return "Hello, World!" }
type TextDecorator struct { text Text }
func (d *TextDecorator) Render() string { return d.text.Render() }
type BoldDecorator struct { TextDecorator }
func NewBoldDecorator(text Text) *BoldDecorator { return &BoldDecorator{TextDecorator{text}} }
func (b *BoldDecorator) Render() string { return "<b>" + b.text.Render() + "</b>" }
type ItalicDecorator struct { TextDecorator }
func NewItalicDecorator(text Text) *ItalicDecorator { return &ItalicDecorator{TextDecorator{text}} }
func (i *ItalicDecorator) Render() string { return "<i>" + i.text.Render() + "</i>" }
func main() { simpleText := &SimpleText{} boldText := NewBoldDecorator(simpleText) italicBoldText := NewItalicDecorator(boldText)
fmt.Println(simpleText.Render()) fmt.Println(boldText.Render()) fmt.Println(italicBoldText.Render()) }
|
这里面的这个struct出现了新的用法
1 2 3
| type ItalicDecorator struct { TextDecorator }
|
这种用法类似于类的继承,允许ItalicDecorator
直接使用TextDecorator
里面的成员函数,里面的成员变量也可以访问