本文主要讲述一种设计思路,组件化架构市面上已经有很多大厂成熟的方案,但是在组件化过程中,偶尔会遇到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. 完整微信小程序授权登录页面教程

    完整微信小程序授权登录页面教程 1.前言 微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方 ...

  2. Java 给 PowerPoint 文档添加背景颜色和背景图片

    在制作Powerpoint文档时,背景是非常重要的,统一的背景能让Powerpoint 演示文稿看起来更加干净美观.本文将详细讲述如何在Java应用程序中使用免费的Free Spire.Present ...

  3. Array(数组)对象-->数组的访问

    1.访问数组: 通过指定数组名以及索引号码,你可以访问某个特定的元素. 格式: 数组对象名[下标] 例如:arr[0]  就是访问数组第一个值 var arr = new Array(3); arr[ ...

  4. 【Selenium03篇】python+selenium实现Web自动化:元素三类等待,多窗口切换,警告框处理,下拉框选择

    一.前言 最近问我自动化的人确实有点多,个人突发奇想:想从0开始讲解python+selenium实现Web自动化测试,请关注博客持续更新! 这是python+selenium实现Web自动化第三篇博 ...

  5. FastAPI框架

    目录 FastAPI框架 安装 基本使用 模版渲染 安装jinja2 基本使用 form表单数据交互 基本数据 文件交互 静态文件配置 FastAPI框架 该框架的速度(天然支持异步)比一般的djan ...

  6. 学习Salesforce | Platform Developer Ⅰ 平台初级开发认证考试指南及备考资源

    一.平台开发人员考试计划 Salesforce平台开发人员初级认证面向具有在Lightning平台上构建自定义应用程序的知识.技能和经验的个人. 该认证考核Lightning平台的基本编程能力,并会使 ...

  7. Problem D. Ice Cream Tower

    题解:二分加贪心,,,二分答案,然后进行判断,判断的时候,首先给每一组配一个最大的球,然后在向每一组里面填球,注意填球的时候要按组进行,每一组先填一个,然后更新每一组内的最小值,方便下一次寻找. #i ...

  8. nodejs一些比较实用的命令

    在学习node的时候是从express开始的,在express中有一个generate,如果在机器上面全局的安装了express-generate的话,可以直接实用[express project_n ...

  9. 解决vue element table行列不齐问题

    全局加入如下样式即可(app.vue): body .el-table th.gutter{ display: table-cell!important; }

  10. JS-Array-新增方法

    1. filter( ) var arr = [5,4,3,2,1]; newarr = arr.filter((item)=>{ return item<3 }) ;  // => ...