手撸 golang 架构设计准则 迪米特法令
缘起
最近温习设计模式
拜读谭勇德的 << 设计模式就该这样学 >>
该书以 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_demeter
type TaskStatus int
const OPENING TaskStatus = 0
const DONE TaskStatus = 1
const CANCLED TaskStatus = 2
const DENIED TaskStatus = 3
type Task struct {
iID int
iStatus 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_demeter
type ITeamLeader interface {CountOpeningTasks() int
}
BadTeamLeader.go
不好的 ITeamLeader 实现, 同时耦合了 Task 和 BadTeamMember 两个类
package law_of_demeter
import "fmt"
type BadTeamLeader struct {
iID int
sName 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_demeter
type BadTeamMember struct {
iID int
sName string
}
func NewBadTeamMember(id int, name string) *BadTeamMember {
return &BadTeamMember{
id,
name,
}
}
func (me *BadTeamMember) countOpeningTasks(lstTasks []*Task) int {
sum := 0
for _,it := range lstTasks {if it.Status() == OPENING {sum++}
}
return sum
}
GoodTeamLerader.go
更好的 ITeamLeader 实现, 只依赖了GoodTeamMember
package law_of_demeter
import "fmt"
type GoodTeamLeader struct {
iID int
sName 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_demeter
type GoodTeamMember struct {
iID int
sName string
}
func NewGoodTeamMember(id int, name string) *GoodTeamMember {
return &GoodTeamMember{
id,
name,
}
}
func (me *GoodTeamMember) countOpeningTasks() int {
sum := 0
tasks := LoadTaskList()
for _,it := range tasks {if it.Status() == OPENING {sum++}
}
return sum
}
law_of_demeter_test.go
单元测试
package main
import "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)
PASS
ok command-line-arguments 0.002s