本文主要讲述一种设计思路,组件化架构市面上已经有很多大厂成熟的方案,但是在组件化过程中,偶尔会遇到2个独立业务子模块间没有相互引用,也需要能直接调用对方的功能,因此我想到通过方法路由来解决,如果还有疑问,可以发邮件到我的邮箱ufolca@163.com或者加我微信号【the51alien】备注一下“简书”,如有不妥之处,还请指正


起源

一次跨部门合作开发APP时遇到一个问题,我们各自开发几个业务组件,A部门有个功能需要直接调用我这边的功能,如果只是打开我这边的界面,可以通过界面路由唤起,这时很容易想到了2种实现

  • 把这个功能抽取到业务组件的基类base组件里

  • 把这个功能代码copy一份到A部门的组件里

这2种方案一种是会让基类组件涉及到业务,另一种如果该业务功能后期有修改得把所有组件里copy这块代码的都要改一次,均不是完美的解决方案


启发

联想到页面路由方案,既然页面我可以通过url来调用,方法为什么不可以呢,那我就试试通过代理的模式来实现

base模块IMethodBaseProxy.java
public interface IMethodBaseProxy {
/**
* @param modelTag 模块别名
* @param methodName 方法名
* @param params 方法参数数组
* @return true 当前代理类方法支持该方法并且执行 ;false 当前代理类里不支持该方法名和参数
*/
boolean envoke(String modelTag, String methodName, Object[] params); /**
* @return 返回代理模块名
*/
String getTag();
}
复制代码
base模块ModelProxyManager.java-用来管理和执行所有业务模块的方法代理
public class ModelProxyManager {
private HashMap<String, IMethodBaseProxy> methodProxyMap = new HashMap<>(); public static class ModelProxyManagerHolder {
public static ModelProxyManager instance = new ModelProxyManager();
} public static ModelProxyManager getInstance() {
return ModelProxyManagerHolder.instance;
} private ModelProxyManager() {
}
public void addMethodProxy(IMethodBaseProxy proxy) {
if (methodProxyMap != null) {
methodProxyMap.put(proxy.getTag(), proxy);
}
} /**
* 遍历寻找对应的方法所在的代理类并且进行调用
*
* @param modelTag 模块别名
* @param methodName 方法名
* @param paras 方法参数
* @return
*/
public boolean envoke(String modelTag, String methodName, Object[] paras) {
if (methodProxyMap != null && methodProxyMap.containsKey(modelTag)) {
IMethodBaseProxy methodProxy = methodProxyMap.get(modelTag);
if (methodProxy.envoke(modelTag, methodName, paras)) {
return true;
}
}
return false;
}
}
复制代码
a模块AMethodProxy.java-将a模块的业务功能通过方法代理暴露出来
public class AMethodProxy implements IMethodBaseProxy {
@Override
public boolean envoke(String modelTag, String methodName, Object[] params) {
if ("test".equals(methodName)) {
test();
return true;
} else if ("testContext".equals(methodName)) {
if (params != null && params.length == 1) {
try {
testContext((Context) params[0]);
return true;
} catch (Exception e) { }
}
} else if ("testCallback".equals(methodName)) {
if (params != null && params.length == 3) {
try {
testCallback((Context) params[0], params[1].toString(), (MethoProxyCallBack) params[2]);
return true;
} catch (Exception e) { }
}
}
return false; } private void testCallback(Context ctx, String s, MethoProxyCallBack callBack) {
if (callBack != null) {
callBack.callBack("{\"" + s + "\":\"success\"}");
}
} private void testContext(Context ctx) {
Toast.makeText(ctx, "moudle-a.testContext()", Toast.LENGTH_SHORT).show();
} private void test() {
Log.d("moudle-a.test()", "success");
} @Override
public String getTag() {
return "a";
}
}
复制代码
b模块BTest.java-用来调用a模块的业务方法
public class BTest {

    public void test() {
ModelProxyManager.getInstance().envoke("a", "test", null);
} public void testContext(Context context) {
ModelProxyManager.getInstance().envoke("a", "testContext", new Object[]{context});
} public void testCallback(Context context, String s, MethoProxyCallBack callBack) {
ModelProxyManager.getInstance().envoke("a", "testCallback", new Object[]{context, s, callBack});
}
}
复制代码
app模块MainActivity.java-用来测试跨组件方法调用
public class MainActivity extends AppCompatActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//模块A的方法代理添加到总的方法代理中心
ModelProxyManager.getInstance().addMethodProxy(new AMethodProxy());
final BTest bTest = new BTest();
findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bTest.test();
}
});
findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bTest.testContext(MainActivity.this);
}
});
findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bTest.testCallback(MainActivity.this, "bbb", new MethoProxyCallBack() {
@Override
public void callBack(String jsonStr) {
Toast.makeText(MainActivity.this, "moudle-a.testCallback()===para:" + jsonStr, Toast.LENGTH_SHORT).show();
}
});
}
});
}
}
复制代码

传送门

demo地址

APP路由还能这样玩的更多相关文章

  1. 呛口大话APP 移动端到底怎么玩

    [上海站]活动概况 时间:2016年04月09日13:30-16:30 地点:上海市黄浦区黄陂北路227号中区广场105室WE+联合办公空间 主办:APICloud.七牛.听云 报名网址:http:/ ...

  2. Java 11 已发布,String 还能这样玩!

    在文章<Java 11 正式发布,这 8 个逆天新特性教你写出更牛逼的代码>中,我有介绍到 Java 11 的八个新特性,其中关于 String 加强部分,我觉得有点意思,这里单独再拉出来 ...

  3. Android事件总线还能怎么玩?

    作者简介:何红辉,Android工程师,现任职于友盟. 顾名思义,AndroidEventBus是一个Android平台的事件总线框架,它简化了Activity.Fragment.Service等组件 ...

  4. Java 12 骚操作, String居然还能这样玩!

    Java 13 都快要来了,12必须跟栈长学起! Java 13 即将发布,新特性必须抢先看! 栈长之前在Java技术栈微信公众号分享过<Java 11 已发布,String 还能这样玩!> ...

  5. tornado实现不同app路由分发

    tornado实现app路由分发 from tornado import ioloop from tornado.httpserver import HTTPServer from tornado.w ...

  6. Apache DolphinScheduler 需要的sudo,还可以这么玩,长见识了!

    Apache DolphinScheduler(incubator)需要的sudo,还可以这么玩,长见识了! 在新一代大数据任务调度 - Apache DolphinScheduler(以下简称dol ...

  7. Word揭秘:公式还能这么玩!

    如今办公室里用Word来处理资料文档一种再普遍不过的现象了,学校的老师出试卷也离不开它.用Word编辑公式也是一个非常的技巧,玩转Word的同时,你玩转公式了吗?想要在Word中编辑公式,可不是说说就 ...

  8. Docker竟然还能这么玩?商业级4G代理搭建实战!

    时间过得真快,距离这个系列的上一篇文章<商业级4G代理搭建指南[准备篇]>发布的时间已经过了两个星期了,上个星期由于各种琐事缠身,周二开始就没空写文章了,所以就咕咕咕了. 那么在准备篇中, ...

  9. 继 “多闪”后“飞聊”再被diss?其实社交还能这么玩

    近日头条低调上线了新的社交APP——飞聊,目前在AppStore社交排行榜第7位.但很多人使用了之后都觉得新产品的各个功能都让人想起其他的产品.兴趣小组让人想到豆瓣的兴趣小组,生活动态让人想到微博动态 ...

随机推荐

  1. 计算机网络协议,IPV4数据报分析

    一.IP数据报结构分析 1.整体结构 一个IP数据报由首部和数据两部分组成. 首部的前一部分固定长20字节,这是所有IP数据报必须具有的:在首部的固定部分后面是一些可选字段,其长度是可变的. IP数据 ...

  2. 汇编刷题:根据公式 Z=(X+Y)*8-X)/4 计算Z的结果(本题将结果放在AL寄存器里)

    DATA SEGMENT X DB 10 Y DB 20 Z DB 00 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DAT ...

  3. 抽签小程序,妈妈再也不用担心谁洗碗(分配任务)了,so easy

    背景 今天谁炒菜,谁洗碗,谁买菜...啊,Boss说用抽签吧,于是有了下图 这样存在作弊的问题(记住棍子特征,谁先,谁后抽等等)于是有了这个抽签小程序(当然小程序我一个人控制,我想不想作弊看心情了) ...

  4. Web前端必备-Nginx知识汇总

    一.Nginx简介 Nginx是一个高性能.轻量级的Web和反向代理服务器, 其特点是占有内存及资源少.抗并发能力强. Nginx安装简单.配置简洁.启动快速便捷.支持热部署.支持 SSL.拥有高度模 ...

  5. PHP获取当天、本周、本月、本季度、本年度时间

    function get_date($date, $t = 'd', $n = 0) { if ($t == 'd') { $firstday = date('Y-m-d 00:00:00', str ...

  6. undefined 和 not defined

    概念上的解释: undefined是javascript语言中定义的五个原始类中的一个,换句话说,undefined并不是程序报错,而是程序允许的一个值. not defined是javascript ...

  7. 中国剩余定理(CRT)

    只看懂了CRT,EXCRT待补.... 心得:记不得这是第几次翻CRT了,每次都有迷迷糊糊的.. 中国剩余定理用来求解类似这样的方程组: 求解的过程中用到了同余方程. x=a1( mod x1) x= ...

  8. Linux编辑利器-Vim

    在大学时代,Vim 的大名就已如雷贯耳,但由于它陡峭的学习曲线,一直望而却步.等真正开始学习之后,发现并没有想象中的复杂,也没有所谓的瓶颈,只要在实际写代码中强迫自己使用就可以了,无形中就会形成习惯. ...

  9. 11. this.setState更新问题

    this.setState是异步的,所以在this.setState之后不能立刻得到最新的state数据关于如何获取最新的数据,有如下三种方法 1.回调函数 this.setState({ xxx:' ...

  10. 一站式轻量级框架 Spring

    Spring 简介 Spring 是一个轻量级的 Java 开发框架,它是为了解决企业应用开发的复杂性而创建的.Spring 的核心是控制反转(IoC)和面向切面编程(AOP).简单来说,Spring ...