设计模式之代理模式

99 阅读2分钟

「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。

静态代理模式

对于代理模式的理解我们可以通过生活中的一些例子来说明,比如生活中,一般自己去租房比较难,所以可以通过中介去进行代理,将其用代码模拟,就是一个简单的代理模式。

interface House{

    public void Rent();
}

class Customer implements House{

    @Override
    public void Rent() {
        System.out.println("租个房子");
    }
}

class Agency implements House{
    House obj;
    Agency(House obj){
        this.obj = obj;
    }
    @Override
    public void Rent() {
        System.out.println("我是中介");
        obj.Rent();
        System.out.println("租房成功!");
    }
}

动态代理模式

静态代理的维护成本是比较高的,比如在House接口中新增一个方法sell,那么所有的实现了House接口的类都需要新增,这样会造成工作量比较大,所以需要使用动态代理模式\

interface House{

    public void Rent();
}

interface Car{
    public void drive();
}

class Customer implements House,Car{

    @Override
    public void Rent() {
        System.out.println("租个房子");
    }

    @Override
    public void drive() {
        System.out.println("开车");
    }
}
public class Main {
    public static void main(String[] args) {
            Car car = (Car) Proxy.newProxyInstance(Customer.class.getClassLoader(), Customer.class.getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Object result = method.invoke(new Customer(),args);
                    System.out.println(method.getName()+"被调用了");
                    return result;
                }
            });
            car.drive();
    }
}

通过Proxy.newProxyInstance动态生成了一个对象,这个对象没有任何的我们写的类原型,将其强制转换成Car 后可以调用Car的方法从而最终会调用invoke方法。

该过程可以理解为通过newProxyInstance方法,拿到类加载器,根据传入的接口字节码,会生成一个实现了这些接口的对象,在这个对象中的对应接口方法中会调用invoke方法。

生成的对象的模板可以理解为下面的类

class Agency implements House,Car{
    //InvocationHandler是重写的匿名类对象
    InvocationHandler mInvocationHandler;

    Agency(InvocationHandler invocationHandler){
        mInvocationHandler = invocationHandler;
    }

    @Override
    public void Rent() {
        try {
            Method method = House.class.getMethod("Rent",String.class);
            mInvocationHandler.invoke(this,method,new Object[]{});
        }catch (Exception e){
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }

    @Override
    public void drive() {
        try {
            Method method = Car.class.getMethod("drive",String.class);
            mInvocationHandler.invoke(this,method,new Object[]{});
        }catch (Exception e){
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}