设计模式笔记 - 代理模式

114 阅读2分钟

代理模式是一种结构型设计模式,让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。


解决什么问题?

如果某些操作是很费时的,而且这些操作的结果是可以复用的。在理想情况下, 我们希望将代码直接放入对象的类中, 但这并非总是能实现: 比如类可能是第三方封闭库的一部分。或希望在不修改原有类的情况下,引入新功能。此时可以考虑创建代理类,接管客户端与服务端之间的交互过程,实现更多定制化的功能。


实现步骤:

  • 根据需求创建服务类接口
  • 创建代理类, 代理负责创建服务并对其整个生命周期进行管理
  • 代理类实现服务类接口, 在大部分情况下, 代理在完成一些任务后应将工作委派给服务对象
  • 可以考虑新建一个构建方法来判断客户端可获取的是代理还是实际服务
  • 可以考虑为服务对象实现延迟初始化

优点:

  • 你可以在客户端毫无察觉的情况下控制服务对象
  • 如果客户端对服务对象的生命周期没有特殊要求, 你可以对生命周期进行管理
  • 即使服务对象还未准备好或不存在, 代理也可以正常工作
  • 开闭原则。 你可以在不对服务或客户端做出修改的情况下创建新代理

缺点:

  • 代码可能会变得复杂, 因为需要新建许多类
  • 服务响应可能会延迟

下面是实现代码:

package main

import "fmt"

type service interface {
	doSomething()
}

type server struct {
	addr string
}

func (s *server) doSomething() {
	fmt.Println("server doSomething")
}

func newServer(addr string) *server {
	return &server{
		addr: addr,
	}
}

type proxy struct {
	addr string
	s    service
}

func newProxy(addr string) *proxy {
	p := proxy{}
	p.setup(addr)
    return &p
}

func (p *proxy) setup(addr string) {
	p.addr = addr
	p.s = newServer(addr)
}

func (p *proxy) doSomething() {
	p.s.doSomething()
}

func (p *proxy) authentication(passwd string) bool {
	if passwd != "123456" {
		return false
	}

	return true
}

func main() {
	passwd := "123456"

	p := newProxy("127.0.0.1:8888")
	if !p.authentication(passwd) {
		fmt.Printf("passwd: %s invalid!!!", passwd)
		return
	}

	p.doSomething()
}

参考