📚 设计模式概述
在 Go 语言中,虽然缺乏传统的类和继承机制,但通过接口、结构体和组合,我们同样可以优雅地实现各种面向对象设计模式。
🎯 代理模式 (Proxy Pattern)
原理介绍
代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。
核心思想
- 控制访问:控制对真实对象的访问权限
- 延迟初始化:在需要时才创建昂贵对象
- 附加功能:在不修改原对象的情况下添加额外功能
设计方案
go
package main
import (
"fmt"
"log"
"time"
)
// 抽象主题接口
type Image interface {
Display()
GetSize() int
}
// 真实主题 - 高分辨率图像
type HighResolutionImage struct {
filename string
width int
height int
data []byte
}
func NewHighResolutionImage(filename string) *HighResolutionImage {
fmt.Printf("Loading high resolution image: %s\n", filename)
// 模拟昂贵的加载过程
time.Sleep(2 * time.Second)
return &HighResolutionImage{
filename: filename,
width: 4000,
height: 3000,
data: make([]byte, 1024*1024*10), // 10MB 模拟数据
}
}
func (img *HighResolutionImage) Display() {
fmt.Printf("Displaying high resolution image: %s (%dx%d)\n",
img.filename, img.width, img.height)
}
func (img *HighResolutionImage) GetSize() int {
return len(img.data)
}
// 虚拟代理 - 延迟加载图像
type ImageProxy struct {
filename string
realImage *HighResolutionImage
}
func NewImageProxy(filename string) *ImageProxy {
return &ImageProxy{
filename: filename,
}
}
func (proxy *ImageProxy) Display() {
if proxy.realImage == nil {
proxy.realImage = NewHighResolutionImage(proxy.filename)
}
proxy.realImage.Display()
}
func (proxy *ImageProxy) GetSize() int {
if proxy.realImage == nil {
return 0 // 尚未加载
}
return proxy.realImage.GetSize()
}
// 保护代理 - 访问控制
type ProtectedImageProxy struct {
realImage Image
userRole string
}
func NewProtectedImageProxy(image Image, userRole string) *ProtectedImageProxy {
return &ProtectedImageProxy{
realImage: image,
userRole: userRole,
}
}
func (proxy *ProtectedImageProxy) Display() {
if !proxy.hasAccess() {
log.Printf("Access denied for user role: %s", proxy.userRole)
return
}
proxy.realImage.Display()
}
func (proxy *ProtectedImageProxy) GetSize() int {
if !proxy.hasAccess() {
return 0
}
return proxy.realImage.GetSize()
}
func (proxy *ProtectedImageProxy) hasAccess() bool {
// 简单的权限检查逻辑
return proxy.userRole == "admin" || proxy.userRole == "user"
}
// 使用示例
func main() {
fmt.Println("=== 虚拟代理示例 ===")
proxy := NewImageProxy("vacation_photo.jpg")
fmt.Println("1. 创建代理,但真实图像尚未加载")
fmt.Printf("图像大小: %d bytes\n", proxy.GetSize())
fmt.Println("2. 首次显示 - 触发真实图像加载")
proxy.Display()
fmt.Printf("图像大小: %d bytes\n", proxy.GetSize())
fmt.Println("\n=== 保护代理示例 ===")
realImage := NewHighResolutionImage("sensitive_document.jpg")
// 普通用户
userProxy := NewProtectedImageProxy(realImage, "guest")
fmt.Println("普通用户尝试访问:")
userProxy.Display()
// 管理员
adminProxy := NewProtectedImageProxy(realImage, "admin")
fmt.Println("管理员尝试访问:")
adminProxy.Display()
}
🎨 装饰器模式 (Decorator Pattern)
原理介绍
装饰器模式动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
核心思想
- 透明扩展:在不改变接口的情况下扩展功能
- 组合优于继承:通过组合而非继承来扩展功能
- 运行时装饰:可以在运行时动态添加或移除功能
设计方案
go
package main
import (
"fmt"
"strings"
)
// 组件接口
type DataSource interface {
Write(data string)
Read() string
}
// 具体组件
type FileDataSource struct {
filename string
content string
}
func NewFileDataSource(filename string) *FileDataSource {
return &FileDataSource{
filename: filename,
}
}
func (f *FileDataSource) Write(data string) {
fmt.Printf("Writing to file %s: %s\n", f.filename, data)
f.content = data
}
func (f *FileDataSource) Read() string {
fmt.Printf("Reading from file %s: %s\n", f.filename, f.content)
return f.content
}
// 基础装饰器
type DataSourceDecorator struct {
wrappee DataSource
}
func NewDataSourceDecorator(source DataSource) *DataSourceDecorator {
return &DataSourceDecorator{
wrappee: source,
}
}
func (d *DataSourceDecorator) Write(data string) {
d.wrappee.Write(data)
}
func (d *DataSourceDecorator) Read() string {
return d.wrappee.Read()
}
// 加密装饰器
type EncryptionDecorator struct {
*DataSourceDecorator
}
func NewEncryptionDecorator(source DataSource) *EncryptionDecorator {
return &EncryptionDecorator{
DataSourceDecorator: NewDataSourceDecorator(source),
}
}
func (e *EncryptionDecorator) Write(data string) {
encrypted := e.encrypt(data)
e.DataSourceDecorator.Write(encrypted)
}
func (e *EncryptionDecorator) Read() string {
encrypted := e.DataSourceDecorator.Read()
return e.decrypt(encrypted)
}
func (e *EncryptionDecorator) encrypt(data string) string {
// 简单的加密示例 - 实际应用中应使用真正的加密算法
result := make([]byte, len(data))
for i := 0; i < len(data); i++ {
result[i] = data[i] + 1 // 简单的凯撒密码
}
fmt.Printf("加密: %s -> %s\n", data, string(result))
return string(result)
}
func (e *EncryptionDecorator) decrypt(data string) string {
result := make([]byte, len(data))
for i := 0; i < len(data); i++ {
result[i] = data[i] - 1
}
fmt.Printf("解密: %s -> %s\n", data, string(result))
return string(result)
}
// 压缩装饰器
type CompressionDecorator struct {
*DataSourceDecorator
}
func NewCompressionDecorator(source DataSource) *CompressionDecorator {
return &CompressionDecorator{
DataSourceDecorator: NewDataSourceDecorator(source),
}
}
func (c *CompressionDecorator) Write(data string) {
compressed := c.compress(data)
c.DataSourceDecorator.Write(compressed)
}
func (c *CompressionDecorator) Read() string {
compressed := c.DataSourceDecorator.Read()
return c.decompress(compressed)
}
func (c *CompressionDecorator) compress(data string) string {
// 简单的压缩示例 - 运行长度编码
var result strings.Builder
count := 1
for i := 1; i <= len(data); i++ {
if i < len(data) && data[i] == data[i-1] {
count++
} else {
result.WriteByte(data[i-1])
fmt.Fprintf(&result, "%d", count)
count = 1
}
}
fmt.Printf("压缩: %s -> %s\n", data, result.String())
return result.String()
}
func (c *CompressionDecorator) decompress(data string) string {
// 简单的解压缩
var result strings.Builder
i := 0
for i < len(data) {
char := data[i]
i++
count := 0
for i < len(data) && data[i] >= '0' && data[i] <= '9' {
count = count*10 + int(data[i]-'0')
i++
}
for j := 0; j < count; j++ {
result.WriteByte(char)
}
}
fmt.Printf("解压缩: %s -> %s\n", data, result.String())
return result.String()
}
// 使用示例
func main() {
fmt.Println("=== 基础文件操作 ===")
file := NewFileDataSource("test.txt")
file.Write("Hello, World!")
fmt.Printf("读取: %s\n\n", file.Read())
fmt.Println("=== 加密文件操作 ===")
encryptedFile := NewEncryptionDecorator(file)
encryptedFile.Write("Sensitive Data")
fmt.Printf("读取: %s\n\n", encryptedFile.Read())
fmt.Println("=== 压缩文件操作 ===")
compressedFile := NewCompressionDecorator(file)
compressedFile.Write("AAAAABBBCCCDDE")
fmt.Printf("读取: %s\n\n", compressedFile.Read())
fmt.Println("=== 加密+压缩组合 ===")
superFile := NewEncryptionDecorator(
NewCompressionDecorator(
NewFileDataSource("super.txt"),
),
)
superFile.Write("Top Secret Message")
fmt.Printf("读取: %s\n", superFile.Read())
}
🔄 适配器模式 (Adapter Pattern)
原理介绍
适配器模式将一个类的接口转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
核心思想
- 接口转换:将不兼容的接口转换为目标接口
- 桥接功能:在不同接口之间建立桥梁
- 复用现有代码:无需修改现有代码即可集成新功能
设计方案
go
package main
import (
"fmt"
"strconv"
)
// 目标接口 - 现代支付系统期望的接口
type ModernPaymentGateway interface {
ProcessPayment(amount float64, currency string) (string, error)
Refund(transactionID string) (string, error)
}
// 适配者 - 遗留的支付系统
type LegacyPaymentSystem struct{}
func (l *LegacyPaymentSystem) MakePayment(amountInCents int, currencyCode string) (int, string) {
fmt.Printf("Legacy system: Processing payment of %d cents in %s\n", amountInCents, currencyCode)
// 模拟处理逻辑
transactionID := 12345
return transactionID, "SUCCESS"
}
func (l *LegacyPaymentSystem) CancelPayment(transactionID int) string {
fmt.Printf("Legacy system: Cancelling transaction %d\n", transactionID)
return "REFUNDED"
}
func (l *LegacyPaymentSystem) ValidateCurrency(currencyCode string) bool {
supportedCurrencies := map[string]bool{
"USD": true, "EUR": true, "GBP": true,
}
return supportedCurrencies[currencyCode]
}
// 适配器 - 将遗留系统适配到现代接口
type LegacyPaymentAdapter struct {
legacySystem *LegacyPaymentSystem
}
func NewLegacyPaymentAdapter() *LegacyPaymentAdapter {
return &LegacyPaymentAdapter{
legacySystem: &LegacyPaymentSystem{},
}
}
func (a *LegacyPaymentAdapter) ProcessPayment(amount float64, currency string) (string, error) {
// 转换金额格式:美元转分
amountInCents := int(amount * 100)
// 验证货币
if !a.legacySystem.ValidateCurrency(currency) {
return "", fmt.Errorf("unsupported currency: %s", currency)
}
// 调用遗留系统
transactionID, status := a.legacySystem.MakePayment(amountInCents, currency)
if status != "SUCCESS" {
return "", fmt.Errorf("payment failed with status: %s", status)
}
return fmt.Sprintf("TXN-%d", transactionID), nil
}
func (a *LegacyPaymentAdapter) Refund(transactionID string) (string, error) {
// 解析交易ID
if len(transactionID) <= 4 {
return "", fmt.Errorf("invalid transaction ID: %s", transactionID)
}
idStr := transactionID[4:] // 去掉 "TXN-" 前缀
id, err := strconv.Atoi(idStr)
if err != nil {
return "", fmt.Errorf("invalid transaction ID format: %s", transactionID)
}
// 调用遗留系统
status := a.legacySystem.CancelPayment(id)
if status != "REFUNDED" {
return "", fmt.Errorf("refund failed with status: %s", status)
}
return fmt.Sprintf("REFUND-%s", transactionID), nil
}
// 另一个适配者示例 - 第三方支付服务
type ThirdPartyPaymentService struct{}
func (t *ThirdPartyPaymentService) Pay(amount float64, currency string, options map[string]interface{}) map[string]interface{} {
fmt.Printf("ThirdParty: Processing payment of %.2f %s\n", amount, currency)
return map[string]interface{}{
"success": true,
"payment_id": "TP-" + fmt.Sprintf("%d", 67890),
"status": "completed",
"fee_amount": amount * 0.029, // 2.9% 手续费
}
}
func (t *ThirdPartyPaymentService) ReversePayment(paymentID string) map[string]interface{} {
fmt.Printf("ThirdParty: Reversing payment %s\n", paymentID)
return map[string]interface{}{
"success": true,
"refund_id": "REF-" + paymentID,
}
}
// 第三方支付适配器
type ThirdPartyPaymentAdapter struct {
thirdPartyService *ThirdPartyPaymentService
}
func NewThirdPartyPaymentAdapter() *ThirdPartyPaymentAdapter {
return &ThirdPartyPaymentAdapter{
thirdPartyService: &ThirdPartyPaymentService{},
}
}
func (a *ThirdPartyPaymentAdapter) ProcessPayment(amount float64, currency string) (string, error) {
result := a.thirdPartyService.Pay(amount, currency, nil)
if !result["success"].(bool) {
return "", fmt.Errorf("third party payment failed")
}
return result["payment_id"].(string), nil
}
func (a *ThirdPartyPaymentAdapter) Refund(transactionID string) (string, error) {
result := a.thirdPartyService.ReversePayment(transactionID)
if !result["success"].(bool) {
return "", fmt.Errorf("third party refund failed")
}
return result["refund_id"].(string), nil
}
// 支付处理器 - 使用统一的现代接口
type PaymentProcessor struct {
gateway ModernPaymentGateway
}
func NewPaymentProcessor(gateway ModernPaymentGateway) *PaymentProcessor {
return &PaymentProcessor{
gateway: gateway,
}
}
func (p *PaymentProcessor) MakePayment(amount float64, currency string) {
fmt.Printf("\n处理支付: %.2f %s\n", amount, currency)
transactionID, err := p.gateway.ProcessPayment(amount, currency)
if err != nil {
fmt.Printf("支付失败: %v\n", err)
return
}
fmt.Printf("支付成功! 交易ID: %s\n", transactionID)
}
func (p *PaymentProcessor) ProcessRefund(transactionID string) {
fmt.Printf("\n处理退款: %s\n", transactionID)
refundID, err := p.gateway.Refund(transactionID)
if err != nil {
fmt.Printf("退款失败: %v\n", err)
return
}
fmt.Printf("退款成功! 退款ID: %s\n", refundID)
}
// 使用示例
func main() {
fmt.Println("=== 遗留支付系统适配器 ===")
legacyAdapter := NewLegacyPaymentAdapter()
processor1 := NewPaymentProcessor(legacyAdapter)
processor1.MakePayment(99.99, "USD")
processor1.ProcessRefund("TXN-12345")
fmt.Println("\n=== 第三方支付适配器 ===")
thirdPartyAdapter := NewThirdPartyPaymentAdapter()
processor2 := NewPaymentProcessor(thirdPartyAdapter)
processor2.MakePayment(49.99, "EUR")
processor2.ProcessRefund("TP-67890")
// 测试错误情况
fmt.Println("\n=== 错误处理测试 ===")
processor1.MakePayment(100.00, "JPY") // 不支持的货币
processor1.ProcessRefund("INVALID-ID") // 无效的交易ID
}
🏢 外观模式 (Facade Pattern)
原理介绍
外观模式为子系统中的一组接口提供一个统一的高层接口。外观模式定义了一个更高级的接口,使得子系统更容易使用。
核心思想
- 简化接口:提供简单的接口来隐藏子系统的复杂性
- 解耦:将客户端与子系统解耦
- 统一入口:为复杂的子系统提供统一的访问点
设计方案
go
package main
import (
"fmt"
"log"
)
// 复杂的子系统 - 视频转换系统
// 视频编解码器
type VideoCodec interface {
Decode(file []byte) []byte
Encode(data []byte) []byte
}
type H264Codec struct{}
func (h *H264Codec) Decode(file []byte) []byte {
fmt.Println("H264: 解码视频文件")
return []byte("解码后的原始数据")
}
func (h *H264Codec) Encode(data []byte) []byte {
fmt.Println("H264: 编码视频数据")
return []byte("H264编码的视频数据")
}
type VP9Codec struct{}
func (v *VP9Codec) Decode(file []byte) []byte {
fmt.Println("VP9: 解码视频文件")
return []byte("解码后的原始数据")
}
func (v *VP9Codec) Encode(data []byte) []byte {
fmt.Println("VP9: 编码视频数据")
return []byte("VP9编码的视频数据")
}
// 音频处理系统
type AudioProcessor struct{}
func (a *AudioProcessor) ExtractAudio(videoData []byte) []byte {
fmt.Println("音频处理: 从视频中提取音频")
return []byte("提取的音频数据")
}
func (a *AudioProcessor) NormalizeAudio(audioData []byte) []byte {
fmt.Println("音频处理: 标准化音频")
return []byte("标准化后的音频数据")
}
func (a *AudioProcessor) MixAudio(audio1, audio2 []byte) []byte {
fmt.Println("音频处理: 混合音频轨道")
return []byte("混合后的音频数据")
}
// 视频处理系统
type VideoProcessor struct{}
func (v *VideoProcessor) ResizeVideo(data []byte, width, height int) []byte {
fmt.Printf("视频处理: 调整分辨率 %dx%d\n", width, height)
return data
}
func (v *VideoProcessor) ApplyFilter(data []byte, filter string) []byte {
fmt.Printf("视频处理: 应用滤镜 '%s'\n", filter)
return data
}
func (v *VideoProcessor) AdjustBitrate(data []byte, bitrate int) []byte {
fmt.Printf("视频处理: 调整码率 %d kbps\n", bitrate)
return data
}
// 文件输出系统
type FileOutputSystem struct{}
func (f *FileOutputSystem) CreateFile(filename string) {
fmt.Printf("文件输出: 创建文件 %s\n", filename)
}
func (f *FileOutputSystem) WriteData(data []byte) {
fmt.Printf("文件输出: 写入数据 (%d bytes)\n", len(data))
}
func (f *FileOutputSystem) CloseFile() {
fmt.Println("文件输出: 关闭文件")
}
// 质量检查系统
type QualityControl struct{}
func (q *QualityControl) CheckVideoQuality(data []byte) bool {
fmt.Println("质量检查: 检查视频质量")
return true
}
func (q *QualityControl) CheckAudioSync(videoData, audioData []byte) bool {
fmt.Println("质量检查: 检查音视频同步")
return true
}
func (q *QualityControl) GenerateReport() string {
fmt.Println("质量检查: 生成质量报告")
return "质量检查报告: 所有检查通过"
}
// 外观类 - 视频转换外观
type VideoConversionFacade struct {
h264Codec *H264Codec
vp9Codec *VP9Codec
audioProcessor *AudioProcessor
videoProcessor *VideoProcessor
fileOutput *FileOutputSystem
qualityControl *QualityControl
}
func NewVideoConversionFacade() *VideoConversionFacade {
return &VideoConversionFacade{
h264Codec: &H264Codec{},
vp9Codec: &VP9Codec{},
audioProcessor: &AudioProcessor{},
videoProcessor: &VideoProcessor{},
fileOutput: &FileOutputSystem{},
qualityControl: &QualityControl{},
}
}
// 简化后的高级接口
func (f *VideoConversionFacade) ConvertVideoSimple(inputFile []byte, outputFormat string) error {
fmt.Printf("开始视频转换: %s 格式\n", outputFormat)
fmt.Println("==================================")
var codec VideoCodec
switch outputFormat {
case "h264":
codec = f.h264Codec
case "vp9":
codec = f.vp9Codec
default:
return fmt.Errorf("不支持的格式: %s", outputFormat)
}
// 解码原始视频
rawVideo := codec.Decode(inputFile)
// 处理视频
processedVideo := f.videoProcessor.ResizeVideo(rawVideo, 1920, 1080)
processedVideo = f.videoProcessor.ApplyFilter(processedVideo, "contrast")
// 处理音频
audioData := f.audioProcessor.ExtractAudio(rawVideo)
audioData = f.audioProcessor.NormalizeAudio(audioData)
// 编码最终视频
finalVideo := codec.Encode(processedVideo)
// 质量检查
if !f.qualityControl.CheckVideoQuality(finalVideo) {
return fmt.Errorf("视频质量检查失败")
}
if !f.qualityControl.CheckAudioSync(finalVideo, audioData) {
return fmt.Errorf("音视频同步检查失败")
}
// 输出文件
f.fileOutput.CreateFile("output." + outputFormat)
f.fileOutput.WriteData(finalVideo)
f.fileOutput.CloseFile()
report := f.qualityControl.GenerateReport()
fmt.Printf("转换完成: %s\n", report)
fmt.Println("==================================")
return nil
}
func (f *VideoConversionFacade) ConvertForWeb(inputFile []byte, quality string) error {
fmt.Printf("开始Web视频转换: %s 质量\n", quality)
fmt.Println("==================================")
var width, height, bitrate int
switch quality {
case "low":
width, height, bitrate = 640, 360, 500
case "medium":
width, height, bitrate = 1280, 720, 1500
case "high":
width, height, bitrate = 1920, 1080, 4000
default:
return fmt.Errorf("不支持的质量级别: %s", quality)
}
// 使用 VP9 编码器进行Web优化
rawVideo := f.vp9Codec.Decode(inputFile)
// 视频处理
processedVideo := f.videoProcessor.ResizeVideo(rawVideo, width, height)
processedVideo = f.videoProcessor.AdjustBitrate(processedVideo, bitrate)
// 音频处理
audioData := f.audioProcessor.ExtractAudio(rawVideo)
audioData = f.audioProcessor.NormalizeAudio(audioData)
// 编码
finalVideo := f.vp9Codec.Encode(processedVideo)
// 质量检查
f.qualityControl.CheckVideoQuality(finalVideo)
// 输出
f.fileOutput.CreateFile(fmt.Sprintf("web_%s_quality.vp9", quality))
f.fileOutput.WriteData(finalVideo)
f.fileOutput.CloseFile()
fmt.Println("Web视频转换完成!")
fmt.Println("==================================")
return nil
}
func (f *VideoConversionFacade) ExtractAudioOnly(inputFile []byte, outputFormat string) error {
fmt.Printf("提取音频: %s 格式\n", outputFormat)
fmt.Println("==================================")
// 解码视频
rawVideo := f.h264Codec.Decode(inputFile)
// 提取和处理音频
audioData := f.audioProcessor.ExtractAudio(rawVideo)
audioData = f.audioProcessor.NormalizeAudio(audioData)
// 输出音频文件
f.fileOutput.CreateFile("audio_only." + outputFormat)
f.fileOutput.WriteData(audioData)
f.fileOutput.CloseFile()
fmt.Println("音频提取完成!")
fmt.Println("==================================")
return nil
}
// 使用示例
func main() {
facade := NewVideoConversionFacade()
// 模拟输入文件数据
inputVideo := []byte("模拟视频文件数据")
fmt.Println("🎬 视频转换系统演示")
fmt.Println("==================")
// 简单转换
err := facade.ConvertVideoSimple(inputVideo, "h264")
if err != nil {
log.Fatal(err)
}
fmt.Println()
// Web优化转换
err = facade.ConvertForWeb(inputVideo, "medium")
if err != nil {
log.Fatal(err)
}
fmt.Println()
// 仅提取音频
err = facade.ExtractAudioOnly(inputVideo, "mp3")
if err != nil {
log.Fatal(err)
}
}
📊 模式对比总结
| 模式 | 目的 | 适用场景 | Go 实现特点 |
|---|---|---|---|
| 代理模式 | 控制访问,延迟加载 | 权限控制、缓存、虚拟代理 | 接口实现,组合代替继承 |
| 装饰器模式 | 动态添加功能 | 功能扩展,不修改原代码 | 接口嵌入,多层装饰 |
| 适配器模式 | 接口转换 | 集成遗留代码,第三方库适配 | 实现目标接口,包装适配者 |
| 外观模式 | 简化复杂系统 | 子系统封装,提供统一接口 | 结构体组合,简化方法 |
🎯 最佳实践建议
- 接口设计:优先定义简洁清晰的接口
- 组合优于继承:充分利用 Go 的组合特性
- 单一职责:每个模式专注于单一目的
- 错误处理:在适配器和外观中妥善处理错误
- 测试友好:通过接口使得模式易于测试