美文网首页程序员设计模式
手撸golang 架构设计原则 迪米特法则

手撸golang 架构设计原则 迪米特法则

作者: 老罗话编程 | 来源:发表于2021-01-27 14:08 被阅读0次

    手撸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
    

    相关文章

      网友评论

        本文标题:手撸golang 架构设计原则 迪米特法则

        本文链接:https://www.haomeiwen.com/subject/ndhazktx.html