古法编程: 代理模式

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

故事背景

卓贾暗恋李娇娇,想送礼物追求她,但不好意思亲自出马,于是请好友戴励帮忙代理送礼物。没想到戴励在帮忙过程中近水楼台先得月,爱上了李娇娇,最终向卓贾坦白。

代理模式

代理模式(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 动态代理 无需手动编写代理类,代码简洁 只能代理接口,不能代理类

适用场景

  • 远程代理:为远程对象提供本地代表
  • 虚拟代理:延迟加载大对象
  • 安全代理:控制原始对象的访问权限
  • 智能引用:访问对象时执行额外操作

(待续...)

相关推荐
文心快码BaiduComate2 小时前
Comate搭载Kimi K2.6,长程13h!
前端·后端·程序员
Pkmer2 小时前
古法编程: 责任链模式
后端·设计模式
KevinSheeran2 小时前
Rust高级代码题 - 手写一个 LRU Cache
后端
Java女侠_9年实战3 小时前
JVM调优“瞎调”——没分析GC日志,乱改堆内存参数导致OOM
后端
做个文艺程序员3 小时前
流式输出(SSE)在 Spring Boot 中的实现【OpenClAW + Spring Boot 系列 第3篇】
java·spring boot·后端
你有医保你先上3 小时前
Elasticsearch Go 客户端
后端·elasticsearch·go
Kel4 小时前
LangChain.js 架构设计深度剖析
人工智能·设计模式·架构
回家路上绕了弯4 小时前
IDEA 2026.1 ACP 全攻略:一键集成多 AI 智能体,解锁开发效率新上限
后端
曹牧4 小时前
Spring :component-scan
java·后端·spring