夜已降临,而我还在发呆......一位古法编程在天台的发呆。

故事背景
卓贾暗恋李娇娇,想送礼物追求她,但不好意思亲自出马,于是请好友戴励帮忙代理送礼物。没想到戴励在帮忙过程中近水楼台先得月,爱上了李娇娇,最终向卓贾坦白。
代理模式
代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问。在本例中,MyProxy(戴励)作为 Pursuit(卓贾)的代理,帮助他执行送礼物等行为,但代理可以在执行过程中加入自己的逻辑。
代理模式,在这个案例中就像中介一样,认识代理追求者和被追求者。相比于装饰器模式,代理模式代理的是行为,而装饰器更多的是在原基础上有选择,有顺序地扩展新功能。
模式结构
- Subject(抽象主题) :
IGiveGift接口,定义送礼物的方法 - RealSubject(真实主题) :
Pursuit类,真正的追求者 - Proxy(代理) :
MyProxy类,代理对象
类图

代码实现
抽象主题接口
java
public interface IGiveGift {
void giveDolls();
void giveFlowers();
void giveChocolate();
}
真实主题类
java
public class Pursuit implements IGiveGift {
private SchoolGirl mm;
private final String name;
public Pursuit(String name) {
this.name = name;
}
public void setMm(SchoolGirl mm) {
this.mm = mm;
}
public void giveDolls() {
System.out.println(this.mm.name() + ",你好!送你洋娃娃。");
}
public void giveFlowers() {
System.out.println(this.mm.name() + ",你好!送你鲜花。");
}
public void giveChocolate() {
System.out.println(this.mm.name() + ",你好!送你巧克力。");
}
}
代理类(手动实现)
java
public class MyProxy implements IGiveGift {
private final String name = "戴励";
private Pursuit gg;
private SchoolGirl mm;
private int count = 0;
public MyProxy(SchoolGirl mm) {
this.gg = new Pursuit("卓贾");
this.mm = mm;
gg.setMm(mm);
}
@Override
public void giveDolls() {
System.out.printf("%s帮%s:%n", name, gg.getName());
this.gg.giveDolls();
checkLove();
}
@Override
public void giveFlowers() {
System.out.printf("%s帮%s:%n", name, gg.getName());
this.gg.giveFlowers();
checkLove();
}
@Override
public void giveChocolate() {
System.out.printf("%s帮%s:%n", name, gg.getName());
this.gg.giveChocolate();
checkLove();
}
private void checkLove() {
this.count++;
if (count >= 3) {
System.out.printf("%s: 对不起好兄弟(%s),我爱上了她(%s)%n",
this.name, this.gg.getName(), this.mm.name());
}
}
}
测试代码
java
public class MyproxyTest {
public static void main(String[] args) {
SchoolGirl girl = new SchoolGirl("李娇娇");
MyProxy proxy = new MyProxy(girl);
proxy.giveFlowers();
proxy.giveChocolate();
proxy.giveFlowers();
}
}
运行结果
makefile
戴励帮卓贾:
李娇娇,你好!送你鲜花。
戴励帮卓贾:
李娇娇,你好!送你巧克力。
戴励帮卓贾:
李娇娇,你好!送你鲜花。
戴励: 对不起好兄弟(卓贾),我爱上了她(李娇娇)
JDK 动态代理
除了手动编写代理类,Java 还提供了 java.lang.reflect.Proxy 来动态生成代理对象,无需为每个真实主题类手动编写代理。
动态代理工厂
java
public class JDKProxyFactory {
public static IGiveGift createProxy(SchoolGirl mm, Pursuit gg) {
return (IGiveGift) Proxy.newProxyInstance(
gg.getClass().getClassLoader(),
gg.getClass().getInterfaces(),
new InvocationHandler() {
private int count = 0;
private final String name = "戴励";
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
count++;
System.out.printf("%s帮%s:%n", this.name, gg.getName());
Object result = method.invoke(gg, args);
if (count >= 3) {
System.out.printf("%s: 对不起好兄弟(%s),我爱上了她(%s)%n",
this.name, gg.getName(), mm.name());
}
return result;
}
});
}
}
测试代码
java
public class JDKProxyTest {
public static void main(String[] args) {
SchoolGirl schoolGirl = new SchoolGirl("李娇娇");
Pursuit pursuit = new Pursuit("卓贾");
pursuit.setMm(schoolGirl);
IGiveGift daiLi = JDKProxyFactory.createProxy(schoolGirl, pursuit);
daiLi.giveChocolate();
daiLi.giveDolls();
daiLi.giveFlowers();
}
}
运行结果
makefile
戴励帮卓贾:
李娇娇,你好!送你巧克力。
戴励帮卓贾:
李娇娇,你好!送你洋娃娃。
戴励帮卓贾:
李娇娇,你好!送你鲜花。
戴励: 对不起好兄弟(卓贾),我爱上了她(李娇娇)
两种方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 手动代理(MyProxy) | 代码直观,易于理解和调试 | 需要为每个类编写代理,代码冗余 |
| JDK 动态代理 | 无需手动编写代理类,代码简洁 | 只能代理接口,不能代理类 |
适用场景
- 远程代理:为远程对象提供本地代表
- 虚拟代理:延迟加载大对象
- 安全代理:控制原始对象的访问权限
- 智能引用:访问对象时执行额外操作
(待续...)