应用场景
在Android的代码维护当中,经常会涉及到逻辑变更.但是又并不是整个逻辑变更了,往往是类似在之前的操作前面追加逻辑,或者是在之后追加逻辑.对于这样的逻辑,往往是每个类型的操作里面都要变更.
比较笨的方法当然就是挨个去写啦.但是这种体力劳动太低效,太浪费了.在JAVA中,针对这样的应用场景,比较常规的是有两种处理方案:
1.继承,重写方法;
2.装饰模式;
3.动态代理;
1.继承
对于这种方式,是最简单的方式.对于这个方式,大部分开发者都会很简单的就想到.但是这个方式会造成很大部分的垃圾代码,且灵活性并不高,而且还必须知道具体的类才能完成.示例如下:
1.1 写一个普通的类实现一个普通的方法
由于这里写在外面类比较麻烦,所以就直接在一个类中用静态内部类实现.
static class Man{
public void run(){
//一个正常人 跑步的方法
System.out.println("the man is running !");
}
}
1.2 写一个类继承这个类,进行增强
static class SuperMan extends Man{
@Override
public void run() {
//super.run();
System.out.println("the superMan is flying !");
}
}
1.3 运行测试
Man man = new SuperMan();
man.run();
//输出结果 the superMan is flying !
2.装饰模式
在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰者模式,在java中的实现是通过接口来定义,包装类和被包装类实现同一个接口,包装类持有被包装类对象,包装类就可以对被包装类实现增强了.
2.1 接口类定义
interface Waiter{
void server();
}
2.2 被包装类实现
static class Waitress implements Waiter{
@Override
public void server() {
System.out.println("Waitress server !");
}
}
2.3 包装类实现
static class WaitessWrapper implements Waiter{
public Waiter waiter;
public WaitessWrapper(Waiter waiter) {
//为了通用 持有接口类
this.waiter = waiter;
}
@Override
public void server() {
System.out.println("smile");
waiter.server();
System.out.println("smile end !");
}
}
2.4 调用函数
Waiter waiter1 = new Waitress();
waiter1.server();
Waiter waiter2 = new WaitessWrapper(waiter1);
waiter2.server();
//结果显示如下
Waitress server !
smile
Waitress server !
smile end !
3.动态代理
代理机制及特点
1.通过实现 InvocationHandler 接口创建自己的调用处理器;
2.通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
3.通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
4.通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
由于主要目的是实现Android中的应用,因此我就直接附上项目代码进行说明:
private void initListener() {
Object object = Proxy.newProxyInstance(this.getClass()
.getClassLoader(),
this.getClass()
.getInterfaces(),
(Object proxy, Method method, Object[] args) -> {
switch (method.getName()) {
case "onCategory":
case "onName":
case "onShare":
case "onPic":
case "onItemClick":
case "onRefresh":
case "onClick":
case "onOptionsItemSelected":
case "onNavigationItemSelected":
if (isEnvent) {
return null;
}
return method.invoke(NavActivity.this,
args);
case "onOption":
if (isEnvent) {
return null;
}
if (!TDevice.hasInternet()) {
showErrorTip(getString(R.string.footer_type_net_error));
return null;
}
if (WXShareManager.sWXAPI.getWXAppSupportAPI() <= WXShareManager.TIMELINE_SUPPORTED_VERSION) {
AppContext.showToast(R.string.weixin_update);
return null;
}
return method.invoke(NavActivity.this,
args);
}
return method.invoke(NavActivity.this, args);
});
mNavView.setNavigationItemSelectedListener((NavigationView.OnNavigationItemSelectedListener) object);
mFgtMainSrl.setOnRefreshListener((SwipeRefreshLayout.OnRefreshListener) object);
mAdapter.setListener((FileItemAdapter.OnFileItemListener) object);
mCreate.setOnClickListener((View.OnClickListener) object);
mScrollListener = new ScrollListener(null);
mFgtMainRv.addOnScrollListener(mScrollListener);
mCiv.setOnClickListener((View.OnClickListener) object);
mTvUser.setOnClickListener((View.OnClickListener) object);
mFusion.setOnClickListener((View.OnClickListener) object);
mDelete.setOnClickListener((View.OnClickListener) object);
mSeletedAll.setOnClickListener((View.OnClickListener) object);
}
如上,是我项目中的代码.简单说明一下:
1.标记位 isEnvent
是项目中当前是否有操作,在有操作的情况下应该避免别的操作.
2.Proxy.newProxyInstance
返回值 Object
是返回的当前操作执行返回的接口对象.
3.Proxy.newProxyInstance
中参数说明:如下是方法声明
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{}
参数一:ClassLoader loader
类加载器
参数二:Class<?>[] interfaces
代理接口
参数三:InvocationHandler h
对于代理接口的处理对象,主要代码逻辑在这个类中实现,处理逻辑详细看上述例子.
这样实现可以最大限度的简化代码,解耦.而且这样改起来也很方便.在后续代码逻辑的变化中,主要逻辑写在接口方法实现中,追加的逻辑都写在代理对象里面.可以方便随时更改,而且比较统一,找起来也不复杂.