Java代理模式和kotlin代理模式

时间:2022-09-09 20:08:42

简述:

Aspect Oriented Programming 面向切片编程 aop

 

需求目标:

1.在某个项目中你已经写好了一部分代码,现在想要给这一部分代码添加一个新的附加的功能,并且屏蔽原来代码中不想被调用的代码,总结起来就是中间隔离-开闭原则

 

思考一下,为了满足这个要求我们新建一个类用这个类继承原来的接口,我们称这个类为代理类,我们用这个代理类去重写接口的方法,并在方法中调用真实类的方法

吃饭接口:

public interfaceEat {
    voideatSomth();
}

原始的吃早餐类:

public classEatBreckfastimplementsEat{
static  StringTAG=EatBreckfast.class.getSimpleName();
    @Override
    public voideatSomth() {
        Log.e(TAG,"native eat method");
    }
}

代理类

public classConstantProxyimplementsEat {
    static  StringTAG=ConstantProxy.class.getSimpleName();

    EatBreckfasteatBreckfast;

    public ConstantProxy(EatBreckfast eatBreckfast) {
        this.eatBreckfast= eatBreckfast;
    }

    @Override
    public voideatSomth() {
        /**
         * 调用前想执行的动作
         */
        
Log.e(TAG,"eat begin");
        eatBreckfast.eatSomth();
        /**
         *  调用后想执行的动作
         */
    
}
}

其实这个就是所谓静态代理,

但是这样做的弊端是很明显的,由于代理类和真实类 是一一对应的那么有多少个真实类我们就要创建多少个代理类,这样就感觉逻辑混乱,然后会多很多的类,

所以我们需要动态代理

动态代理:

动态代理,基础的可以使用Javajdk的动态代理,jdk动态代理的核心是反射真实类的需要代理的方法。

public classDynamicProxyimplementsInvocationHandler {
static StringTAG=DynamicProxy.class.getSimpleName();
    private Objecttarget;
    public DynamicProxy(Object target) {
        this.target= target;
    }
    /**
     *
     * 系统类的方法
     * 类初始化的时候
     * 被系统自动调用
     *
@paramproxy
     *
@parammethod
     *
@paramargs
     *
@return
     
*@throwsThrowable
     */
    
@Override
    publicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable {
        /**
         *
         * 调用前想执行的动作
         */
        
Log.e(TAG,"eat begin");
        Object result=method.invoke(target,args);
        /**
         * 调用后想执行的动作
         */
        
Log.e(TAG,"eat over");
        return result;
    }
    public<T>TgetProxy(){
            return(T) Proxy.newProxyInstance(target.getClass().getClassLoader()
            ,target.getClass().getInterfaces()
            ,this);
    }
}

 

借助jdkInvocationHandler接口, 我们可以往原始的方法中添加我们需要的操作,通过动态代理方式我们只需要写将需要代理的操作写到代理类的invoke方法中,这样我们只需要将任意的被代理类(真实类)的对象传入代理类中就可以完成这个对真实类的动态代理调用

调用方式:

DynamicProxy dynamicProxyEat=newDynamicProxy(newEatBreckfast());
 Eat eat=(Eat) dynamicProxyEat.getProxy();
eat.eatSomth();
DynamicProxy dynamicProxyDrink=newDynamicProxy(newDrinkWater());
Drink drink=(Drink) dynamicProxyDrink.getProxy();
drink.drinkSomth();

结果打印:

09-06 02:11:57.765 5778-5778/? E/DynamicProxy: eat begin
09-06 02:11:57.765 5778-5778/? E/DynamicProxy: native eat somth
09-06 02:11:57.765 5778-5778/? E/DynamicProxy: eat over
09-06 02:11:57.765 5778-5778/? E/DynamicProxy: eat begin
09-06 02:11:57.765 5778-5778/? E/DynamicProxy: native dink somth
09-06 02:11:57.765 5778-5778/? E/DynamicProxy: eat over


这样我们对于不同的对象欲实现同一功能的代理只需用动态代理类包装这个对象即可

1.优势:不需要每个真实类 对应一个代理类这样 一一对应的关系,省去了很多重复代码

2.缺点:真实类必须继承自某个接口才行用,例如上列中的drinkwater eatbrackfast 分别继承自drink接口和eat接口

Cglib代理

1.优点 不需要真实类继承自某个接口,目标对象可以只是一个单独的对象

2.缺点需要引入三方类库

(没用过,,,不评价)


kotlin 代理

Kotlin 代理

kotlin 中的代理使用关键字 by来实现 (不过貌似没有动态代理?那有个jb用?)

 

public interfaceWash {         // 原始的wash接口
  voidwashSomth();
}

 

真实的实现类

 open classWashDish : Wash {
       valTAG :String?="KotlinProxy"
    override funwashSomth() {
        Log.e(TAG,"native wash somth")
    }

}

 

代理类

class KotlinProxy(wash: Wash) :Wash bywash

kotlinproxy 代理类继承 并使用 by关键字代理wash接口

使用时直接调用

var washdish = WashDish()
  KotlinProxy(washdish)
washdish.washSomth()

查看打印

09-07 04:58:11.912 7472-7472/? E/KotlinProxy: native wash somth