本文最后更新于248 天前,其中的信息可能已经过时,如有错误请发送邮件到lvlvko233@qq.com
代理模式
代理模式是一种结构型设计模式,允许我们控制对其他对象的访问。它通过创建一个代理对象来代表另一个对象,从而在访问原对象时提供额外的功能。
场景示例:网络请求处理
假设我们有一个处理网络请求的系统。我们将使用这个场景来展示三种设计模式的实现。
package main
import "fmt"
// HttpRequester 接口定义了发送 HTTP 请求的方法
type HttpRequester interface {
SendRequest(url string) string
}
// RealHttpRequester 是实际发送 HTTP 请求的结构体
type RealHttpRequester struct{}
func (r *RealHttpRequester) SendRequest(url string) string {
return fmt.Sprintf("Sending real HTTP request to %s", url)
}
// HttpProxy 是 HTTP 请求的代理
type HttpProxy struct {
realRequester *RealHttpRequester
}
func (p *HttpProxy) SendRequest(url string) string {
if p.realRequester == nil {
p.realRequester = &RealHttpRequester{}
}
fmt.Println("Proxy: Logging request")
result := p.realRequester.SendRequest(url)
fmt.Println("Proxy: Logging response")
return result
}
func main() {
proxy := &HttpProxy{}
result := proxy.SendRequest("<https://example.com>")
fmt.Println(result)
}
这段代码展示了代理模式的实现:
HttpRequester
接口定义了SendRequest
方法。RealHttpRequester
实现了实际的 HTTP 请求发送。HttpProxy
作为代理,包装了RealHttpRequester
。它在发送请求前后添加了日志记录功能。- 在
main
函数中,我们使用HttpProxy
来发送请求,而不直接使用RealHttpRequester
。
装饰器模式
装饰器模式是一种结构型设计模式,它允许我们动态地给对象添加新的行为,而不改变其结构。
场景示例:增强的网络请求处理
我们将在前面的例子基础上,使用装饰器模式来添加额外的功能。
package main
import (
"fmt"
"strings"
)
// HttpRequester 接口保持不变
type HttpRequester interface {
SendRequest(url string) string
}
// RealHttpRequester 保持不变
type RealHttpRequester struct{}
func (r *RealHttpRequester) SendRequest(url string) string {
return fmt.Sprintf("Sending real HTTP request to %s", url)
}
// CacheDecorator 是缓存装饰器
type CacheDecorator struct {
requester HttpRequester
cache map[string]string
}
func NewCacheDecorator(r HttpRequester) *CacheDecorator {
return &CacheDecorator{
requester: r,
cache: make(map[string]string),
}
}
func (c *CacheDecorator) SendRequest(url string) string {
if result, found := c.cache[url]; found {
return "From cache: " + result
}
result := c.requester.SendRequest(url)
c.cache[url] = result
return result
}
// CompressionDecorator 是压缩装饰器
type CompressionDecorator struct {
requester HttpRequester
}
func (c *CompressionDecorator) SendRequest(url string) string {
result := c.requester.SendRequest(url)
return "Compressed: " + strings.Replace(result, " ", "", -1)
}
func main() {
realRequester := &RealHttpRequester{}
cachedRequester := NewCacheDecorator(realRequester)
compressedCachedRequester := &CompressionDecorator{requester: cachedRequester}
fmt.Println(compressedCachedRequester.SendRequest("<https://example.com>"))
fmt.Println(compressedCachedRequester.SendRequest("<https://example.com>")) // 这次会从缓存中获取
}
这段代码展示了装饰器模式的实现:
CacheDecorator
添加了缓存功能。它存储请求结果,并在重复请求时返回缓存的结果。CompressionDecorator
添加了压缩功能(这里用简单的去空格来模拟)。- 在
main
函数中,我们将这些装饰器组合起来,创建了一个既有缓存又有压缩功能的 HTTP 请求器。
适配器模式
适配器模式是一种结构型设计模式,它允许不兼容的接口一起工作。
场景示例:适配第三方 HTTP 客户端
假设我们想使用一个第三方的 HTTP 客户端库,但它的接口与我们的 HttpRequester
不兼容。
package main
import "fmt"
// HttpRequester 接口保持不变
type HttpRequester interface {
SendRequest(url string) string
}
// 假设这是第三方库的接口
type ThirdPartyHttpClient interface {
Get(url string) (string, error)
}
// 第三方库的具体实现
type ConcreteThirdPartyClient struct{}
func (c *ConcreteThirdPartyClient) Get(url string) (string, error) {
return fmt.Sprintf("Third party client requesting: %s", url), nil
}
// HttpClientAdapter 适配器
type HttpClientAdapter struct {
thirdPartyClient ThirdPartyHttpClient
}
func (a *HttpClientAdapter) SendRequest(url string) string {
result, err := a.thirdPartyClient.Get(url)
if err != nil {
return "Error: " + err.Error()
}
return "Adapted: " + result
}
func main() {
thirdPartyClient := &ConcreteThirdPartyClient{}
adapter := &HttpClientAdapter{thirdPartyClient: thirdPartyClient}
result := adapter.SendRequest("<https://example.com>")
fmt.Println(result)
}
这段代码展示了适配器模式的实现:
ThirdPartyHttpClient
接口代表第三方库的接口,它与我们的HttpRequester
接口不兼容。ConcreteThirdPartyClient
是第三方库的具体实现。HttpClientAdapter
是适配器,它实现了HttpRequester
接口,但内部使用ThirdPartyHttpClient
来执行实际的请求。- 在
main
函数中,我们创建了一个适配器,使得第三方客户端可以在我们的系统中使用。
三种模式的比较
- 目的:
- 代理模式:控制对对象的访问
- 装饰器模式:动态添加功能
- 适配器模式:使不兼容的接口能够一起工作
- 结构:
- 代理模式:代理和实际对象实现相同的接口
- 装饰器模式:装饰器和被装饰对象实现相同的接口
- 适配器模式:适配器实现目标接口,包含被适配对象
- 使用场景:
- 代理模式:访问控制、延迟初始化、日志记录等
- 装饰器模式:动态添加或移除对象功能
- 适配器模式:集成新的库或API时
- 灵活性:
- 代理模式:相对固定
- 装饰器模式:非常灵活,可以动态组合
- 适配器模式:主要用于接口转换
- 对原有代码的影响:
- 代理模式:通常不改变原有代码
- 装饰器模式:不改变原有代码
- 适配器模式:不改变原有代码,但需要创建新的适配器类
三种模式的共同点和优劣
共同点:
- 都属于结构型设计模式
- 都包装原有对象
- 对客户端保持透明性
- 倾向于使用对象组合而不是继承
- 遵循开闭原则
- 符合单一职责原则
- 在原始对象和客户端之间创建中间层
- 允许在运行时动态改变对象的行为或结构
优劣比较:
- 代理模式:
- 优点:可以控制对对象的访问,增加安全性
- 缺点:可能会增加系统的复杂度
- 装饰器模式:
- 优点:非常灵活,可以动态地添加功能
- 缺点:可能会导致系统中小对象过多
- 适配器模式:
- 优点:可以让不兼容的接口一起工作
- 缺点:有时候可能会增加代码的复杂度
୧(๑•̀⌄•́๑)૭