Java代理模式:静态、动态代理;静态代理和装饰模式的区别

代理

为什么用代理?

  • 有些类不能被修改的,因业务需要需要扩展这个类的功能。使用代理模式,可以基于被代理类不变的前提下,对被代理类的行为进行控制和扩展。
  • 前提:
    1. 被代理类不变(或无法修改)
    2. 被代理类是基于接口的实现,因为代理类也需要实现这个接口。

静态代理

静态代理需要在程序运行之前,实现代理类并增加的业务需要的控制或扩展。

实现
  • 提供一个被代理类的接口
  • 被代理类实现这个接口
  • 代理类实现这个接口
  • 代理类中引用被代理类的对象
示例

例如:老师,他的功能是讲课

1. 定义接口
public interface ITeacher {
    void teach();
}
2. 定义被代理类
public class Teacher implements ITeacher {
    @Override
    public void teach() {
        System.out.println("开始讲课~~~~~~~~~");
    }
}
3. 定义代理类

(1). 在讲课之前让老师说"上课起立!"、讲课之后说"下课!"

public class TeacherProxy implements ITeacher {
    private ITeacher iTeacher;

    public TeacherProxy(ITeacher iTeacher) {
        this.iTeacher = iTeacher;
    }

    @Override
    public void teach() {
        System.out.println("上课起立!");
        iTeacher.teach();
        System.out.println("下课!");
    }
}

(2). 也可以写一个稍复杂点的:假设有老师zhang,喜欢的说"上课起立!“后礼貌地说"请坐下!”

public class TeacherProxy implements ITeacher {
    private ITeacher iTeacher;
	private String name;
    public TeacherProxy(String name) {
        this.name= name;
    }

    @Override
    public void teach() {
	    init();
        System.out.println("上课起立!");
        if(name.equals("zhang")){
        	System.out.println("请坐下!");
		}
        iTeacher.teach();
        System.out.println("下课!");
    }
	
	private void init(){
		if(iTeacher == null){
			iTeacher = new Teacher(); 
		}
	}
}
4. 调用
private static void staticProxyTest() {
    Teacher teacher = new Teacher();
    TeacherProxy teacherProxy = new TeacherProxy(teacher);
    teacherProxy.teach();
}
缺点

不够解耦

动态代理

重点还是在与动态代理的应用和理解上,java为提供了Proxy类帮助实现动态代理,实现起来也很简单。不需要创建代理类,只需要已知被代理类和被代理类的实现接口

实例
1. 定义接口

扩展一下之前的接口,方便测试

public interface ITeacher {
    void teach();
    //老师也会唱歌
    void sing();
    //老师有自己的评分(年度评分评级之类的...)
    int getScore();
}
2. 定义被代理类

扩展一下之前的被代理类,方便测试

public class Teacher implements ITeacher {
    private int score;

    @Override
    public void teach() {
        System.out.println("开始讲课~~~~~~~~~");
    }

    @Override
    public void sing() {
        System.out.println("音乐课,唱首歌~~~~~~~~~~~~~");
    }

    @Override
    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}
3. 调用
    private static void jdkProxyTest() {
        //被代理者
        Teacher teacherDelegatee = new Teacher();
		teacherDelegatee.setScore(88);
        
        ITeacher teacherProxy = (ITeacher) Proxy.newProxyInstance(
	        teacherDelegatee.getClass().getClassLoader(),
	        teacherDelegatee.getClass().getInterfaces(),
	        new InvocationHandler() {
	            @Override
	            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	                //可以通过方法名来区分每次调用对应的新增处理代码
	                String methodName = method.getName();
	                if (methodName.equals("teach")) {
	                    System.out.println("上课起立!");
	                    method.invoke(teacherDelegatee, args);
	                    System.out.println("下课!");
	                }
	
	                if (methodName.equals("sing")) {
	                    System.out.println("上课起立!");
	                    method.invoke(teacherDelegatee, args);
	                    System.out.println("下课!");
	                }
	
	                if (methodName.equals("getScore")) {
	                    Object returnValue = method.invoke(teacherDelegatee, args);
	                    //假设做一个给老师加25分的操作
	                    returnValue = (int) returnValue + 25;
	                    //又返回值的情况
	                    return returnValue;
	                }
	                //默认无返回值
	                return null;
	            }
	        });
        //调用多个方法
        System.out.println("------------------调用 teach()---------------");
        teacherProxy.teach();
        System.out.println("------------------调用 sing()-----------------");
        teacherProxy.sing();
        System.out.println("------------------调用 getScore()-------------");
        //调用有返回值的getScore()
        System.out.println("教师评分:" + teacherProxy.getScore());
    }

其中

  • Proxy.newProxyInstance创建的是ITeacher 对象,其中的参数解释如下:
    • ClassLoader loader,类加载器。被代理类的类加载器。
    • Class<?>[] interfaces,被代理类所实现的接口,这个接口也可以是多个。
    • InvocationHandler h,绑定代理类方法。代理类每调用一次任一方法,h(InvocationHandler)invoke方法对应调用一次
  • 其它说明参见注释。

和装饰模式的比较

静态代理装饰模式比较,发现实现方式几乎一模一样。那么区别在哪里?总结一下常规的说法:

  • 静态代理主要做的是对被代理类增加控制,装饰模式主要是对原有对象的扩展。这主要体现在上面静态代理示例中,定义代理类的(2)种方式中。

其实是可以灵活使用的嘛,不需要那么纠结,在不增加耦合、不出bug的前提下,所有的设计模式都可以根据业务需求混合使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
静态代理、装饰者模式和动态代理都是面向对象编程中的常见设计模式,它们都是用于实现对象间的协作和交互。下面举例说明它们的区别: 1. 静态代理 静态代理是指在编译时就已经确定了代理类和被代理类的关系,代理类在程序运行之前就已经存在。代理类和被代理类都要实现同一个接口或者继承同一个父类,代理类中持有被代理类的实例,通过调用被代理类的方法来实现对被代理类的调用。静态代理的优点是可以在代理类中添加额外的功能,而代理类和被代理类之间的关系在编译时就已经确定,比较稳定。 举例:比如在一个电商网站上,用户下单后需要支付,可以使用静态代理模式,将支付功能封装到一个代理类中,代理类中可以添加一些额外的功能,比如记录日志、发送短信等。 2. 装饰者模式 装饰者模式是指在不改变原有对象的基础上,通过对其进行包装(装饰),来扩展其功能。装饰者模式中有一个抽象组件和多个具体组件,抽象组件定义了被装饰对象的接口,具体组件是被装饰的对象。装饰者可以动态地添加、删除或替换被装饰对象的行为。 举例:比如在一个咖啡店中,原本只有一杯普通的咖啡,但是顾客可以根据自己的喜好选择添加奶油、糖、巧克力等,这些都是装饰者,可以动态地添加、删除或替换。 3. 动态代理 动态代理是指在程序运行时动态地生成代理类,不需要在编译时确定代理类和被代理类的关系,代理类在程序运行时才生成。动态代理需要借助Java的反射机制实现,通过代理类的invoke()方法来调用被代理类的方法。动态代理的优点是可以在运行时动态地生成代理类,比较灵活。 举例:比如在一个WEB应用中,需要根据用户的请求动态地生成不同的代理类,来处理不同的请求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值