设计模式之——Java代理

本文详细介绍了代理模式的概念及其在Java中的应用。包括静态代理与动态代理的区别,并提供了具体的代码实例,帮助读者理解代理模式的工作原理。

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

代理模式
所谓代理,就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口或者抽象类,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
静态代理实例,假设现在需要一个回唱歌跳舞的演员,此时我们就联系他们的经纪人(代理),通过经纪人完成。
首先创建一个代理类和委托类共同的接口Human:

package Proxy01;
public interface Human {
    void sing(float money);
    void dance(float money);
    void eat();
}

接着分别创建代理类和委托类实现这两个接口:

package Proxy01;
public class SpringBrother implements Human {//委托类
    public void sing(float money) {
        System.out.println("拿到钱"+money+"开始唱歌!");
    }
    public void dance(float money) {
        System.out.println("拿到钱"+money+"开始跳舞!");
    }
    public void eat() {
        System.out.println("开始吃饭!");
    }
}
package Proxy01;
public class MiddleMan implements Human {//代理类
   private Human h;
   public MiddleMan(Human h) {
        super();
        this.h = h;
    }
    public void sing(float money) {
        h.sing(money);
    }
    public void dance(float money) {
          h.dance(money);
    }
    public void eat() {
    }
}

测试类

package Proxy01;
public class Main {
    public static void main(String[] args) {
        Human actor=new SpringBrother();
        Human middleman=new MiddleMan(actor);
        middleman.sing(100);
        middleman.dance(2000);
    }
}

以上是实现接口的,同样也可以是继承抽象类:
创建代理类和委托类共同的抽象类Human:

package Proxy02;
public abstract class Human {
    public abstract void sing(float money);
   public abstract void dance(float money);
   public abstract void eat();
}

创建代理类和委托类继承抽象类:

package Proxy02;
public class SpringBrother extends Human {
    public void sing(float money) {
        System.out.println("拿到钱"+money+"开始唱歌!");        
    }
    public void dance(float money) {
        // TODO Auto-generated method stub
        System.out.println("拿到钱"+money+"开始跳舞!");    
    }
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("开始吃饭!");    
    }
}
package Proxy02;

public class MiddleMan extends Human {//代理类
   SpringBrother h=new SpringBrother();
    public void sing(float money) {
        h.sing(money);
    }
    public void dance(float money) {
        h.dance(money);
    }
    public void eat() {

    }
}

测试类:

package Proxy02;
public class Main {
    public static void main(String[] args) {
        Human middleman=new MiddleMan();
        middleman.sing(100);
        middleman.dance(2000);
    }
}

以上两个例子的结果都为:拿到钱100.0开始唱歌,拿到钱2000.0开始跳舞。
动态代理实例
没有写代理类
基于接口的动态代理
被代理对象的类至少实现一个接口
基于子类的动态代理
要借助第三方CGLIB

基于接口的动态代理
首先要创建一个接口。

package Proxy01;
public interface Human {
    void sing(float money);
    void dance(float money);
    void eat();
}
package Proxy03;
public class SpringBrother implements Human{
    public void sing(float money) {
        System.out.println("拿到钱"+money+"开始唱歌!");        
    }
    public void dance(float money) {
        // TODO Auto-generated method stub
        System.out.println("拿到钱"+money+"开始跳舞!");    
    }
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("开始吃饭!");    
    }
}
package Proxy01;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        Human actor=new SpringBrother();
        /*
         * ClassLoader loader:类加载器。固定写法:代理人用相同的类加载器即可
         * Interface[] interfaces:代理对象要实现的接口。固定写法。和被代理人相同即可。
         * InvocationHander h :接口。如何代理,策略设计模式。
         */
        Human middleman=(Human)Proxy.newProxyInstance(actor.getClass().getClassLoader(),actor.getClass().getInterfaces(),new InvocationHandler() {

            @Override
            //匿名内部类,具体策略
            //只要执行任何方法,都会经过该方法
            /*返回值:调用函数的返回值
             * Object arg0:当前代理对象的引用。不是程序员使用的。
             * Method arg1:当前执行的方法
             * Object[] arg2:当前执行方法需要的参数
             */
            public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
                // TODO Auto-generated method stub
                if ("sing".equals(arg1.getName()))
                {
                    float money=(float)arg2[0];
                    if(money>1000)
                    {
                        arg1.invoke(actor, money/2);
                    }
                }
                if ("dance".equals(arg1.getName()))
                {
                    float money=(float)arg2[0];
                    if(money>500)
                    {
                        arg1.invoke(actor, money/2);
                    }
                }
                return null;
            }
        });
        middleman.sing(1000);
        middleman.dance(2000);
    }
}

当被代理对象的类一个接口都没有实现,此时就应该用基于子类的动态代理,要用到第三方jar包cglib。

package Proxy03;
public class SpringBrother{
    public void sing(float money) {
        System.out.println("拿到钱"+money+"开始唱歌!");        
    }
    public void dance(float money) {
        // TODO Auto-generated method stub
        System.out.println("拿到钱"+money+"开始跳舞!");    
    }
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("开始吃饭!");    
    }
}
package Proxy03;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Main {
    public static void main(String[] args) {
        /*
         * Class superclass:父类型
         * Callback callback:如何代理
         */
        SpringBrother actor=new SpringBrother();//类不能是final修饰
        SpringBrother middleman=(SpringBrother) Enhancer.create(SpringBrother.class,new MethodInterceptor() {
            //匿名内部类,具体策略
            //只要执行任何方法,都会经过该方法
            /*返回值:调用函数的返回值
             * Object arg0:当前代理对象的引用。不是程序员使用的。
             * Method arg1:当前执行的方法
             * Object[] arg2:当前执行方法需要的参数
             */
            @Override
            public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
                // TODO Auto-generated method stub
                if ("sing".equals(arg1.getName()))
                {
                    float money=(float)arg2[0];
                    if(money>1000)
                    {
                        arg1.invoke(actor, money/2);
                    }
                }
                if ("dance".equals(arg1.getName()))
                {
                    float money=(float)arg2[0];
                    if(money>500)
                    {
                        arg1.invoke(actor, money/2);
                    }
                }
                return null;
            }
        });
        middleman.sing(100);
        middleman.dance(2000);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值