设计模式之代理模式

97 阅读3分钟

代理模式(Proxy Pattern)是一种常用的设计模式,它用于为其他对象提供一种代理以控制对这个对象的访问。

在代理模式中,一个类(称为代理类)负责为另一个类(称为被代理类)预处理消息、过滤消息、把消息转发给对象等。这样,当客户程序调用被代理类的操作时,实际上执行的是代理类的操作,这样,代理类就可以在执行真正的操作前后做一些额外的工作。

例如,假设有一个图片下载器,可以下载图片到本地。如果要为这个图片下载器添加缓存功能,可以使用代理模式来实现,具体方式是:在代理类中维护一个图片缓存,当客户程序请求下载某张图片时,代理类先检查图片是否已经在缓存中,如果存在,则直接从缓存中获取图片,否则调用被代理类的下载方法下载图片,并将下载到的图片保存到缓存中供下次使用。

下面是一个具体的例子,演示了如何使用代理模式实现一个图片下载器:

  1. 首先,我们定义一个接口ImageDownloader表示图片下载器,该接口提供一个Download方法用于下载图片。
type ImageDownloader interface {
    Download(url string) (image []byte, err error)
}
  1. 然后,我们定义一个结构体RealImageDownloader表示被代理类,该结构体实现了ImageDownloader接口中的Download方法,用于真正地下载图片。
type RealImageDownloader struct {
}

func (d *RealImageDownloader) Download(url string) (image []byte, err error) {
    // 省略具体实现
}
  1. 接着,我们定义一个结构体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实例作为参数传递给它,最后调用CachedImageDownloaderDownload方法下载图片。

通过使用代理模式,我们可以在不改变RealImageDownloader类的情况下为图片下载器添加缓存功能,这样可以很方便地为已有的类添加新的功能。