19-08-07
jdon
目的
为另一个对象提供代理或占位符以控制对它的访问。
说明
想象一座塔,当地巫师去那里学习他们的法术。象牙塔只能通过代理访问,这确保只有前三个巫师可以进入。这里的代理代表了塔台的功能,并添加了访问控制。
简而言之,使用代理模式,类表示另一个类的功能。
维基百科说
代理以其最一般的形式,是一个类,充当其他东西的接口。代理是一个包装器或代理对象,客户端正在调用它以便在后台访问真正的服务对象。使用代理可以简单地转发到真实对象,或者可以提供额外的逻辑。在代理中,可以提供额外的功能,例如,当对真实对象的操作占用大量资源时进行缓存,或者在调用对真实对象的操作之前检查前提条件。
程序化示例
以我们的巫师塔为例。首先我们有巫师塔接口和象牙塔类
public interface WizardTower { void enter(Wizard wizard); } public class IvoryTower implements WizardTower { private static final Logger LOGGER = LoggerFactory.getLogger(IvoryTower.class); public void enter(Wizard wizard) { LOGGER.info("{} enters the tower.", wizard); } } |
然后是一个简单的向导类
public class Wizard { private final String name; public Wizard(String name) { this.name = name; } @Override public String toString() { return name; } } |
然后我们有了代理来添加对向导塔的访问控制
public class WizardTowerProxy implements WizardTower { private static final Logger LOGGER = LoggerFactory.getLogger(WizardTowerProxy.class); private static final int NUM_WIZARDS_ALLOWED = 3; private int numWizards; private final WizardTower tower; public WizardTowerProxy(WizardTower tower) { this.tower = tower; } @Override public void enter(Wizard wizard) { if (numWizards < NUM_WIZARDS_ALLOWED) { tower.enter(wizard); numWizards++; } else { LOGGER.info("{} is not allowed to enter!", wizard); } } } |
这里是塔楼进入场景
WizardTowerProxy proxy = new WizardTowerProxy(new IvoryTower()); proxy.enter(new Wizard("Red wizard")); // Red wizard enters the tower. proxy.enter(new Wizard("White wizard")); // White wizard enters the tower. proxy.enter(new Wizard("Black wizard")); // Black wizard enters the tower. proxy.enter(new Wizard("Green wizard")); // Green wizard is not allowed to enter! proxy.enter(new Wizard("Brown wizard")); // Brown wizard is not allowed to enter! |
适用场景
当需要一个比简单指针更通用或更复杂的对象引用时,代理就适用。下面是代理模式适用的几种常见情况
- 远程代理为不同地址空间中的对象提供本地代理。
- 虚拟代理按需创建昂贵的对象。
- 保护代理控制对原始对象的访问。当对象具有不同的访问权限时,保护代理很有用。
典型用例
- 控制对其他对象的访问
- 延迟初始化
- 实施日志记录
- 方便网络连接
- 计算对对象的引用