Menu
CoddyTech

设计模式简介

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 85 课,共 107 课。

设计模式是解决软件设计中常见问题的可重用方案。它们不是可以直接复制的代码,而是指导你如何组织类型及其交互,以解决特定挑战的模板。

设计模式通常分为三类:

类别用途示例
创建型对象创建机制Singleton、Factory、Builder
结构型将类型组合成更大的结构Adapter、Decorator、Composite
行为型对象之间的通信Observer、Strategy、Command

在 Go 中,设计模式看起来与传统的面向对象编程语言不同。

Go 不使用类或继承,而是通过接口、结构体嵌入和组合来实现这些模式。例如,Java 可能会使用抽象类,而 Go 使用接口。C++ 可能会使用继承,而 Go 使用嵌入。

学习设计模式有助于你识别常见问题,并与其他开发者有效地交流解决方案。当有人提到“这里使用 Strategy 模式”时,整个团队都能理解这种做法,无需长篇解释。

在接下来的几节课中,你将用 Go 实现几种基本模式,从单例和工厂等创建型模式开始,然后学习观察者和策略等行为型模式。

challenge icon

挑战

简单

让我们构建一个简单的通知系统,看看设计模式如何帮助组织代码!你将创建一种结构,今后可以轻松扩展,加入观察者模式或策略模式等设计模式。不过现在,请先专注于建立简洁的接口和类型,遵循良好的面向对象编程原则。

你将把代码分布在 3 个文件中:

  • notifier.go:定义通知系统的核心接口和类型。

    创建一个 Notifier 接口,其中包含一个方法 Send(message string) string,用于返回确认消息。

    实现两种具体的通知器类型:

    • EmailNotifier,包含一个 Address 属性。它的 Send 方法返回 Email to [address]: [message]
    • SMSNotifier,包含一个 PhoneNumber 属性。它的 Send 方法返回 SMS to [phone]: [message]
  • dispatcher.go:创建一个调度器,通过接口与任意通知器配合使用。

    构建一个 NotificationDispatcher 结构体,其中包含一个由 Notifier 接口组成的切片。为它添加以下方法:

    • AddNotifier(n Notifier),用于注册通知器
    • Broadcast(message string) []string,通过所有已注册的通知器发送消息,并返回包含所有确认消息的切片

    还要创建一个 NewNotificationDispatcher() 构造函数,用于返回一个已初始化的调度器。

  • main.go:设置通知器并广播消息。

    读取要创建的通知器数量。对于每个通知器,读取它的类型(email 或 sms)和目标地址(电子邮件地址或电话号码)。将每个通知器添加到调度器中。

    然后读取要广播的消息。通过所有通知器发送这条消息,并将每条确认消息分别打印在单独一行。

输入内容如下:

  • 第 1 行:通知器数量
  • 对于每个通知器:类型(email 或 sms),然后是目标地址
  • 最后一行:要广播的消息

例如,给定以下输入:

3
email
alice@example.com
sms
555-1234
email
bob@example.com
Server maintenance at midnight

你的输出应为:

Email to alice@example.com: Server maintenance at midnight
SMS to 555-1234: Server maintenance at midnight
Email to bob@example.com: Server maintenance at midnight

再例如,给定以下输入:

2
sms
555-9999
sms
555-0000
Meeting canceled

你的输出应为:

SMS to 555-9999: Meeting canceled
SMS to 555-0000: Meeting canceled

这种结构展示了接口如何帮助实现灵活且易于扩展的设计。调度器不需要了解具体的通知器类型,只需要知道它们可以调用 Send。这正是观察者模式和策略模式等设计模式的基础!

亲手试试

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 读取通知器的数量
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	// 创建一个新的分发器
	dispatcher := NewNotificationDispatcher()

	// 读取每个通知器,并将其添加到分发器中
	for i := 0; i < count; i++ {
		notifierType, _ := reader.ReadString('\n')
		notifierType = strings.TrimSpace(notifierType)

		destination, _ := reader.ReadString('\n')
		destination = strings.TrimSpace(destination)

		// TODO: 根据类型创建相应的通知器
		// 并将其添加到分发器中
		// 提示:检查 notifierType 是 "email" 还是 "sms"

	}

	// 读取要广播的消息
	message, _ := reader.ReadString('\n')
	message = strings.TrimSpace(message)

	// TODO: 广播消息并打印每条确认信息

}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器