本文主要讲述一种设计思路,组件化架构市面上已经有很多大厂成熟的方案,但是在组件化过程中,偶尔会遇到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. Vim中实现PHP函数tags跳转

    编译安装ctags 下载地址:http://ctags.sourceforge.net/ 下载文件:ctags-5.8.tar.gz 解压ctags:tar -zxcf ctags-5.8.tar.g ...

  2. 使用mpvue开发小程序如何定义全局变量

    我们创建好mpvue项目之后,找到src/main.js打开在后面添加一行代码 (注意:不能在const app = new Vue(App) 之前添加) Vue.prototype.globalDa ...

  3. C#多线程系列(1):Thread

    目录 1,获取当前线程信息 2,管理线程状态 2.1 启动与参数传递 2.1.1 ParameterizedThreadStart 2.1.2 使用静态变量或类成员变量 2.1.3 委托与Lambda ...

  4. ThinkPHP5中raw的作用

    在tp5中,我们一般在模板中输出变量是这样的:{$test} 但是有时候在有些源码中我们可以看到这样的方式:{$test|raw} 这个时候如果你去找手册会发现,全文基本没有提到这个raw的作用. 那 ...

  5. dp优化---四边形不等式与决策单调性

    四边形不等式 定理1: 设w(x,y)为定义在整数集合上的二元函数,若存在任意整数a,b,c,d(a<=b<=c<=d),并且w(a,d)+w(b,c)>=w(a,c)+w(b ...

  6. C# 基础知识系列- 9 字符串的更多用法(二)

    0. 前言 上一篇文章介绍了字符串自身的一些方法,就是对象方法.在字符串体系中,还有一些是string类提供的静态方法.这两部分构成了字符串体系,当然还有一些三方库为字符串提供了扩展方法. 这里简单的 ...

  7. 很用心的为你写了 9 道 MySQL 面试题

    MySQL 一直是本人很薄弱的部分,后面会多输出 MySQL 的文章贡献给大家,毕竟 MySQL 涉及到数据存储.锁.磁盘寻道.分页等操作系统概念,而且互联网对 MySQL 的注重程度是不言而喻的,后 ...

  8. 2019-06-02 Python之微信好友数据分析以及运用Pyecharts可视化

    一.库的使用说明 pass 二.微信好友信息的获取 def get_friends_info(self): #获取好像信息,返回lis列表 bot = Bot() lis = [['name', 'r ...

  9. Reward 杭电 2647

    Problem Description Dandelion's uncle is a boss of a factory. As the spring festival is coming , he ...

  10. Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述

    Spark SQL模块,主要就是处理跟SQL解析相关的一些内容,说得更通俗点就是怎么把一个SQL语句解析成Dataframe或者说RDD的任务.以Spark 2.4.3为例,Spark SQL这个大模 ...