设计模式简介
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 85 课,共 107 课。
设计模式是解决软件设计中常见问题的可重用方案。它们不是可以直接复制的代码,而是指导你如何组织类型及其交互,以解决特定挑战的模板。
设计模式通常分为三类:
| 类别 | 用途 | 示例 |
|---|---|---|
| 创建型 | 对象创建机制 | Singleton、Factory、Builder |
| 结构型 | 将类型组合成更大的结构 | Adapter、Decorator、Composite |
| 行为型 | 对象之间的通信 | Observer、Strategy、Command |
在 Go 中,设计模式看起来与传统的面向对象编程语言不同。
Go 不使用类或继承,而是通过接口、结构体嵌入和组合来实现这些模式。例如,Java 可能会使用抽象类,而 Go 使用接口。C++ 可能会使用继承,而 Go 使用嵌入。
学习设计模式有助于你识别常见问题,并与其他开发者有效地交流解决方案。当有人提到“这里使用 Strategy 模式”时,整个团队都能理解这种做法,无需长篇解释。
在接下来的几节课中,你将用 Go 实现几种基本模式,从单例和工厂等创建型模式开始,然后学习观察者和策略等行为型模式。
挑战
简单让我们构建一个简单的通知系统,看看设计模式如何帮助组织代码!你将创建一种结构,今后可以轻松扩展,加入观察者模式或策略模式等设计模式。不过现在,请先专注于建立简洁的接口和类型,遵循良好的面向对象编程原则。
你将把代码分布在 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: 广播消息并打印每条确认信息
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Go 在线编译器