缘起
最近复习设计模式
拜读谭勇德的<<设计模式就该这样学>>
该书以java语言演绎了常见设计模式
本系列笔记拟采用golang练习之
迪米特法则
迪米特法则(Law of Demeter, LoD)又叫作最少知道原则(Least KnowledgePrinciple, LKP),指一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的耦合。
_
场景
- TeamLeader每天需要查看未完成的项目任务数
- TeamLeader指派TeamMember进行任务统计
- TeamMember提供对Task的汇总方法, 返回未完成的任务数
- 坏的设计:
- Leader: 我需要统计未完成任务数
- Member: 好的, 我可以统计, 但是任务清单在哪里呢?
- Leader: … 我稍后给你吧
- 好的设计:
- Leader: 我需要统计未完成任务数
- Member: 好的. 任务清单我知道在那里, 我会搞定的
- Leader: 好兵!
Task.go
定义任务信息, 以及加载任务清单的方法
package law_of_demetertype TaskStatus intconst OPENING TaskStatus = 0const DONE TaskStatus = 1const CANCLED TaskStatus = 2const DENIED TaskStatus = 3type Task struct {iID intiStatus TaskStatus}func NewTask(id int, status TaskStatus) *Task {return &Task{id,status,}}func (me *Task) ID() int {return me.iID}func (me *Task) Status() TaskStatus {return me.iStatus}func LoadTaskList() []*Task {tasks := make([]*Task, 0)tasks = append(tasks, NewTask(1, OPENING))tasks = append(tasks, NewTask(2, DONE))tasks = append(tasks, NewTask(3, CANCLED))tasks = append(tasks, NewTask(4, DENIED))return tasks}
ITeamLeader.go
定义TeamLeader的接口
package law_of_demetertype ITeamLeader interface {CountOpeningTasks() int}
BadTeamLeader.go
不好的ITeamLeader实现, 同时耦合了Task和BadTeamMember两个类
package law_of_demeterimport "fmt"type BadTeamLeader struct {iID intsName string}func (me *BadTeamLeader) CountOpeningTasks() int {tasks := LoadTaskList()member := NewBadTeamMember(11, "王Member")sum := member.countOpeningTasks(tasks)fmt.Printf("%v CountOpeningTasks, got %v", me.sName, sum)return sum}
BadTeamMember.go
不好的示例. 统计任务数的实现, 要求过多的参数, 增加调用方的耦合度和使用难度
package law_of_demetertype BadTeamMember struct {iID intsName string}func NewBadTeamMember(id int, name string) *BadTeamMember {return &BadTeamMember{id,name,}}func (me *BadTeamMember) countOpeningTasks(lstTasks []*Task) int {sum := 0for _,it := range lstTasks {if it.Status() == OPENING {sum++}}return sum}
GoodTeamLerader.go
更好的ITeamLeader实现, 只依赖了GoodTeamMember
package law_of_demeterimport "fmt"type GoodTeamLeader struct {iID intsName string}func (me *GoodTeamLeader) CountOpeningTasks() int {member := NewGoodTeamMember(11, "王Member")sum := member.countOpeningTasks()fmt.Printf("%v CountOpeningTasks, got %v", me.sName, sum)return sum}
GoodTeamMember.go
更好的TeamMember, 对外屏蔽了任务列表的获取细节
package law_of_demetertype GoodTeamMember struct {iID intsName string}func NewGoodTeamMember(id int, name string) *GoodTeamMember {return &GoodTeamMember{id,name,}}func (me *GoodTeamMember) countOpeningTasks() int {sum := 0tasks := LoadTaskList()for _,it := range tasks {if it.Status() == OPENING {sum++}}return sum}
law_of_demeter_test.go
单元测试
package mainimport "testing"import (lod "learning/gooop/principles/law_of_demeter")func Test_LOD(t *testing.T) {bl := lod.NewBadTeamLeader(1, "张Leader")bl.CountOpeningTasks()gl := lod.NewGoodTeamLeader(2, "李Leader")gl.CountOpeningTasks()}
测试输出
$ go test -v law_of_demeter_test.go=== RUN Test_LOD张Leader CountOpeningTasks, got 1李Leader CountOpeningTasks, got 1--- PASS: Test_LOD (0.00s)PASSok command-line-arguments 0.002s
