乐趣区

关于golang:手撸golang-架构设计原则-迪米特法则

手撸 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
退出移动版