Go 软件设计之道:1 对不同类型的数据进行分组 #私藏项目实操分享#

简介: Go 软件设计之道:1 对不同类型的数据进行分组 #私藏项目实操分享#

对不同类型的数据进行分组

image.png

重要的是要记住,在 Go 中,没有面向对象的概念,所以子类型或子类的概念真的不存在,这些设计模式应该被避免。 以下是不应该遵循或实施的反模式:

type Animal struct {
    Name string
    IsMammal bool
}

动物类型被声明为一个基础类型,它试图定义所有动物共有的数据。我也尝试向动物提供一些常见的行为。

func (a *Animal) Speak() {
    fmt.Println("UGH!",
    "My name is", a.Name, ", it is", a.IsMammal, "I am a mammal")
}

大多数动物都有以这种或那种方式说话的能力。然而,试图将这种常见的行为仅仅适用于一种动物并没有任何意义。在这一点上,我不知道这种动物发出什么声音,所以我写了 UGH

type Dog struct {
    Animal
    PackFactor int
}

现在,真正的问题开始了。我试图用嵌入的方式使狗拥有动物的一切,而且更多。从表面上看,这似乎是可行的,但也会有问题。既然如此,狗确实有一种特殊的说话方式

unc (d *Dog) Speak() {
    fmt.Println("Woof!",
    "My name is", d.Name,
    ", it is", d.IsMammal,
    "I am a mammal with a pack factor of", d.PackFactor)
}

在说话方法的实现中,我可以把 UGH 换成 Woof 。这就是 具体到狗的说话方式

type Cat struct {
    Animal
    ClimbFactor int
}

如果我打算养一只代表动物的狗,那么我就必须养一只猫。使用嵌入法,猫是动物的一切,而且更多。

func (c *Cat) Speak() {
    fmt.Println("Meow!",
    "My name is", c.Name,
    ", it is", c.IsMammal,
    "I am a mammal with a climb factor of", c.ClimbFactor)
}

在实现 Speak 的方法中,我可以把 UGH 改成 Meow 。这就是具体到猫的说话方式 一切看起来都很好,看起来嵌入提供的功能与其他语言中的继承相同。然后我试着把狗和猫分组,因为它们有共同的DNA,都是动物。

// This does not compile, a Dog and Cat are not an Animal.
animals := []Animal{
    Dog{
        Animal: Animal{
            Name: "Fido",
            IsMammal: true,
        },
        PackFactor: 5,
    },
    Cat{
        Animal: Animal{
        Name: "Milo",
        IsMammal: true,
    },
    ClimbFactor: 4,
    },
}
for _, animal := range animals {
    animal.Speak()
}

当我尝试这样做时,编译器抱怨狗和猫不是动物,这是真的。 嵌入与继承不同,这是我需要远离的模式。 狗是狗,猫是猫,动物是动物。 我不能把狗和猫当作动物来传递,因为它们不是。 这种机制也不是很灵活。 它需要开发人员进行配置,除非我可以访问代码并且可以随着时间的推移进行配置更改,否则这不是很灵活 如果这不是我们构建 Dog 和 Cat 集合的方式,我们如何在 Go 中做到这一点? 这不是通过共同的 DNA 进行分组,而是通过共同的行为进行分组。 行为是关键。

type Speaker interface {
    Speak()
}

如果我使用一个接口,那么我可以定义我想要对不同类型的数据进行分组的通用行为方法集:

speakers := []Speaker{
    &Dog{
        Animal: Animal{
            Name: "Fido",
            IsMammal: true,
        },
        PackFactor: 5,
    },
    &Cat{
        Animal: Animal{
            Name: "Milo",
            IsMammal: true,
        },
        ClimbFactor: 4,
    },
}
for _, speaker := range speakers {
    speaker.Speak()
}

在新的代码中,我现在可以根据狗和猫的共同行为集将它们分组。的行为,也就是狗和猫能说话的事实,把它们归为一类。 事实上,Animal 类型确实是类型污染,因为声明一个类型只是为了共享一组公共状态是一种方式,应该避免.

type Dog struct {
    Name string
    IsMammal bool
    PackFactor int
}
type Cat struct {
    Name string
    IsMammal bool
    ClimbFactor int
}

在这种特殊情况下,我宁愿看到动物类型被删除,字段被复制并粘贴到狗和猫类型中。稍后我将有关于更好的模式的说明,以消除这些情况的发生。 以下是原始代码中的代码异类:

  • Animal 类型提供了一个可重用状态的抽象层。
  • 程序永远不需要创建或单独使用 Animal 类型的值。
  • 泛化了 Animal 类型的 Speak 方法的实现。
  • 永远不会调用 Animal 类型的 Speak 方法。

总结

关于声明类型的指南:

  • 声明代表新事物或独特事物的类型。
  • 不要仅仅为了可读性而创建别名。
  • 验证任何类型的值是单独创建或使用的。
  • 嵌入类型不是因为我需要状态,而是因为我们需要行为。
  • 如果我不考虑行为,我就会将自己锁定在未来不进行级联代码更改就无法成长的设计中。
  • 作为现有类型的别名或抽象的问题类型。
  • 唯一目的是共享公共状态的问题类型。


相关文章
|
6月前
|
JSON 安全 前端开发
类型安全的 Go HTTP 请求
类型安全的 Go HTTP 请求
|
3月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
68 4
|
3月前
|
Go
go语言常量的类型
【10月更文挑战第20天】
32 2
|
5月前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
6月前
|
存储 算法 Java
Go 通过 Map/Filter/ForEach 等流式 API 高效处理数据
Go 通过 Map/Filter/ForEach 等流式 API 高效处理数据
|
6月前
|
数据采集 缓存 IDE
Go中遇到http code 206和302的获取数据的解决方案
文章提供了解决Go语言中处理HTTP状态码206(部分内容)和302(重定向)的方案,包括如何获取部分数据和真实请求地址的方法,以便程序员能快速完成工作,享受七夕时光。
258 0
Go中遇到http code 206和302的获取数据的解决方案
|
6月前
|
安全 Go
|
6月前
|
存储 安全 程序员
|
6月前
|
编译器 Go 开发者
Go 在编译时评估隐式类型的优点详解
【8月更文挑战第31天】
41 0
|
6月前
|
存储 编译器 Go