设计模式 -(10)静态代理(static proxy)

本文介绍了如何在不修改原有代码的基础上,通过静态代理模式来实现方法执行时间的统计和日志记录。首先通过子类继承实现简单的时间统计,然后引入接口和聚合实现更灵活的静态代理,最后讨论了如何调整代理顺序以改变执行逻辑,并提及了Java动态代理在代理多个接口时的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计模式 -(10)静态代理(static proxy)

前言

如下,下面有一个类 Programmer1 ,其中有一个 action 方法,现在有一个需求,在不改变 Programmer1 代码前提下统计 action 方法花费时间,应该如何做?

public class Programmer1 {

    public void action() {
        System.out.println("programming...");
    }

    public static void main(String[] args) {
        new Programmer1().action();
    }
}

如下,通过子类继承的方式很容易实现:

public class Programmer2 extends Programmer1 {

    public void action() {
        long start = System.currentTimeMillis();
        super.action();
        System.out.println("action 方法耗时:" + (System.currentTimeMillis() - start));
    }

    public static void main(String[] args) {
        new Programmer2().action();
    }
}
programming...
action 方法耗时:1

现在情况有变,如果在统计 action 方法时长前后需要加上日志应该如何做?很容易想到再在编写一个类继承 Programmer2 ,如下:

public class Programmer3 extends Programmer2 {

    public void action() {
        System.out.println("action begin...");
        super.action();
        System.out.println("action end ...");
    }

    public static void main(String[] args) {
        new Programmer3().action();
    }
}
action begin...
programming...
action 方法耗时:0
action end ...

但是现在又有一个新的需求,统计时间的动作要在日志打印之前开始执行,这样应该怎么实现呢,难道又要将上面两个类再实现一遍吗,显然这种方式不适合也不灵活,因为统计时间和记录日志本来就是两个不同的动作,它们理想的状况应该是可以自由叠加使用的

以聚合的方式实现静态代理

聚合 即一个类中某个属性引用指向另外一个类的对象
以接口形式定义 action 方法可以让聚合实现更加灵活,如下定义 Programme 接口:

public interface Programme {

    void action();
}

Programmer 实现 Programme 接口:

public class Programmer implements Programme {

    @Override
    public void action() {
        System.out.println("programming...");
    }

    public static void main(String[] args) {
        new Programmer().action();
    }
}

对 Programmer 的方法调用时长统计代理可以通过聚合的方式实现,如下:ProgrammerTimeProxy 类有一个 Programme 类型引用

public class ProgrammerTimeProxy implements Programme{

    private Programme programmer;

    public ProgrammerTimeProxy(Programme programmer) {
        this.programmer = programmer;
    }

    @Override
    public void action() {
        long start = System.currentTimeMillis();
        programmer.action();
        System.out.println("action 方法耗时:" + (System.currentTimeMillis() - start));
    }

    public static void main(String[] args) {
        new ProgrammerTimeProxy(new Programmer()).action();
    }
}

同理,日志统计的代理可以这样实现:

public class ProgrammerLogProxy implements Programme {

    private Programme programmer;

    public ProgrammerLogProxy(Programme programmer) {
        this.programmer = programmer;
    }

    @Override
    public void action() {
        System.out.println("action begin...");
        programmer.action();
        System.out.println("action end ...");
    }

    public static void main(String[] args) {
        new ProgrammerLogProxy(new ProgrammerTimeProxy(new Programmer())).action();
    }
}
action begin...
programming...
action 方法耗时:0
action end ...

如果想改变日志代理和统计时长的代理的执行顺序,则只需要调换 ProgrammerLogProxy ,ProgrammerTimeProxy 实例化顺序即可,如下:

new ProgrammerTimeProxy(new ProgrammerLogProxy(new Programmer())).action();
action begin...
programming...
action end ...
action 方法耗时:1

代理类中使用 接口 Programme 作为引用类型充分利用了 Java 多态的思想

以上方式只能代理 Programme 这一个接口,所以称之为静态代理,如何代理任意一个接口?这时候可以使用 jdk 动态代理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值