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

本文来自:简书

感谢作者:ioly

查看原文:golang 架构设计原则 迪米特法则

相关阅读 >>

Golang 优秀框架有哪些

性能优化+架构迭代升级 Go读书社区web开发与架构优化

2021年放弃python选择Go的原因

Go reflect

Golang底层是c语言吗?

grpc-quick start

清晰架构(clean architecture)的Go微服务: 程序设计

运行Golang程序提示进程无法启动

Go语言函数引用传递值

Golang 创建型设计模式 原型模式

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...