代理模式(Proxy Pattern)是一种常用的设计模式,它用于为其他对象提供一种代理以控制对这个对象的访问。
在代理模式中,一个类(称为代理类)负责为另一个类(称为被代理类)预处理消息、过滤消息、把消息转发给对象等。这样,当客户程序调用被代理类的操作时,实际上执行的是代理类的操作,这样,代理类就可以在执行真正的操作前后做一些额外的工作。
例如,假设有一个图片下载器,可以下载图片到本地。如果要为这个图片下载器添加缓存功能,可以使用代理模式来实现,具体方式是:在代理类中维护一个图片缓存,当客户程序请求下载某张图片时,代理类先检查图片是否已经在缓存中,如果存在,则直接从缓存中获取图片,否则调用被代理类的下载方法下载图片,并将下载到的图片保存到缓存中供下次使用。
下面是一个具体的例子,演示了如何使用代理模式实现一个图片下载器:
- 首先,我们定义一个接口
ImageDownloader表示图片下载器,该接口提供一个Download方法用于下载图片。
type ImageDownloader interface {
Download(url string) (image []byte, err error)
}
- 然后,我们定义一个结构体
RealImageDownloader表示被代理类,该结构体实现了ImageDownloader接口中的Download方法,用于真正地下载图片。
type RealImageDownloader struct {
}
func (d *RealImageDownloader) Download(url string) (image []byte, err error) {
// 省略具体实现
}
- 接着,我们定义一个结构体
CachedImageDownloader表示代理类,该结构体包含一个RealImageDownloader类型的字段,用于保存被代理类的实例。该结构体实现了ImageDownloader接口中的Download方法,在方法中,首先检查图片是否已经在缓存中,如果存在,则直接从缓存中获取图片,否则调用被代理类的下载方法下载图片,并将下载到的图片保存到缓存中供下次使用。
type CachedImageDownloader struct {
// 内部维护一个RealImageDownloader类型的实例
realImageDownloader ImageDownloader
// 缓存
cache map[string][]byte
}
func (d *CachedImageDownloader) Download(url string) (image []byte, err error) {
// 先检查图片是否已经在缓存中
image, ok := d.cache[url]
if ok {
// 图片已经在缓存中,直接返回缓存中的图片
return image, nil
}
// 图片不在缓存中,调用被代理类的下载方法下载图片
image, err = d.realImageDownloader.Download(url)
if err != nil {
return nil, err
}
// 下载成功,将图片保存到缓存中
d.cache[url] = image
return image, nil
}
最后,我们可以通过下面的代码来使用上面定义的代理类:
// 创建RealImageDownloader实例
realImageDownloader := &RealImageDownloader{}
// 创建CachedImageDownloader实例
cachedImageDownloader := &CachedImageDownloader{
realImageDownloader: realImageDownloader,
cache: make(map[string][]byte),
}
// 调用CachedImageDownloader的Download方法下载图片
image, err := cachedImageDownloader.Download("http://example.com/image.png")
if err != nil {
fmt.Println(err)
} else {
fmt.Println(len(image))
}
4.在上面的代码中,我们先创建了一个RealImageDownloader实例,然后创建一个CachedImageDownloader实例并将RealImageDownloader实例作为参数传递给它,最后调用CachedImageDownloader的Download方法下载图片。
通过使用代理模式,我们可以在不改变RealImageDownloader类的情况下为图片下载器添加缓存功能,这样可以很方便地为已有的类添加新的功能。