消息耦合还是接口耦合



最近公司准备开发一个新产品,需要重新设计一套新的框架,但是就这框架中各模块的通信方式,大家产生了争论,主要集中在各模块的交互方式是消息耦合还是接口耦合。

需求大概这样,我们需要封装一套客户端SDK, 暴露一系列API给外部用,而这套SDK内部会有很多模块组成,这些模块之间相互会有交互。

第一种设计是基于接口耦合,框架如下:


这种接口方式的设计要点是:
a. 各模块以类似COM组件的方式封装和暴露接口,也就是说模块会以接口的形式暴露接口,并且以Sink的方式通知外部事件。比如模块A的接口如下
class  IA
{
public :
     virtual  void  fun1() = 0;
     virtual  void  fun2() = 0;
     .
     virtual  void  int  AdviseSink(IASink* pSink) = 0;
     virtual  void  bool  UnAdviseSink( int  nCooki) = 0;
}

class  IASink
{
public :
     virtual  void  Event1() = 0;
     virtual  void  Event2() = 0;
     .
}
b. 有一个统一的模块管理平台来管理所有模块,可以通过该平台查询和加载需要的模块,然后后得到相应的接口指针进行操作。
c. 各模块间的交互全都通过直接调用其他模块的接口或是订阅该模块的Sink来实现。

第二种设计是基于消息耦合,框架如下:

这种消息方式的设计要点是:
a. 各个模块只有一个消息处理接口。 
     class  IMessageHandler
    {
     public :
         virtual  void  ProcessMessage(Message& msg) = 0;
    };
b. 中间的消息总线提供消息的订阅和分发,各个模块会向消息总线注册自己感兴趣的消息。
c. 需要调用某个模块接口 或是 触发某个事件时,都是通过向消息总线发送消息的方式, 然后由订阅消息的模块执行。

上面2种架构的设计方式各有优劣,下面我们来简单比较一下:
(1)耦合性: 尽管基于接口的耦合已经降低了耦合性,但是相比消息来说,显然是消息方式耦合性更弱。
(2)可扩展性: 某个模块新增加一个接口, 接口方式需要新加接口函数,而消息方式只需要新加一个消息类型。即使新增加一个模块,消息方式只是新增加几个消息处理类型,非常方便。所以可扩展性来说,显然也是消息方式占优。
(3)性能: 接口方式是直接调用,可是消息方式需要经过消息总线过滤分发, 显然性能上接口方式更高。 
(4)编码安全性,接口方式是强类型,接口一修改,编译时就能很快发现问题;消息方式却是弱类型,消息修改后,有可能要到运行时才能发现问题, 另外很多消息内容要做强制了类型转换才能使用。
(5)文档要求: 显然接口方式相对比较清晰,消息的话每个消息都要详细定义,并且严格按照该定义执行。
(6)可调试性: 显然接口方式要方便些,消息很可能不小心就会引起混乱。
(7)监控过滤方便性:消息方式走同一总线,可以很方便的增加过滤和监控功能, 接口方式则因为各个模块interface和Sink各不相同,增加这些功能没那么方便。
(8)跨线程或是跨进程,甚至跨机器调用:显然接口方式基本做不到,消息方式的话只要修改总线就可以做到。
(9)异步支持: 消息方式可以很方便的支持异步,接口方式则做不到。

经过上面的比较, 我们可以得出一些结论:
消息方式的强项是耦合性和扩展性,以及监控的方便性,个人感觉比较适合于Server端的大规模应用。
接口方式的强项是性能高效以及开发的方便性, 比较适用于同一进程内客户端的小规模应用。

但是大部分时候, 对于架构师或是公司领导,他们会更关注可耦合性和可扩展性,所以他们会倾向于选择消息方式,尽管有时可能不是那么适用。

另外,个人觉得编译时静态类型检测是C++的优势,能让我们高效而可靠的开发程序,我们不应该放弃这些优势而去把C++当作弱类型的动态语言来使用,我在  软命令接口的适用场合  一文也有相关描述。

最后,对于该框架的设计,其实我个人倾向于上面2种方式的结合, 即各个模块的入接口(调用接口)走接口方式,而各模块内部触发的事件走消息总线的方式,虽然没人采用这种方式,还是在这里记录一下。

一个多月了,消息还是接口,领导们老大们关于走何种架构还在争论中, 我等小兵就默默等待吧 ...

呵呵,不知道各位看客会作何选择?
posted on 2012-10-12 22:50  Richard Wei 阅读(2277)  评论(5)   编辑  收藏  引用 所属分类:  架构体系

FeedBack:
#  re: 消息耦合还是接口耦合[未登录]
2012-10-13 21:58 |  123
反驳下:

多核技术发展到现在,接口比消息性能好显然是说不通的。毕竟消息的方式更有利于并行。
另外,个人觉得接口方式虚函数一大堆,各种继承,也不明白开发能有多方便。

最后关于接口方式的结论,出发点也不明确,既然是“同一进程内客户端的小规模应用”,接口方式也显得太大了,难道是为了模式而模式?   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-13 22:28 |  Richard Wei
@123
我们是客户端应用,各模块内部却确实会有多线程,但是各模块间的调用及事件触发都是跑在主线程里,所以这种情况下,如果走消息,基本上要给每个消息维护一个数组,内部保存哪些人订阅了该消息,当该消息到达时进行依次分发,所以这里无论是内存大小还是性能都会比接口直接调用消耗更多。

接口每个方法都有各自不同的明确的参数定义, 消息的话因为要求所有消息参数一致,所以会导致参数含义不明确,内部保存的指针需要强制转换才能使用。

"客户端小规模应用";是相对“大规模Server集群”, 其实我们要做的东西本身也挺大挺复杂,好几十人同时开发。   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-14 15:56 |  irons
我觉得接口更作为一个模块内的设计,而模块间还是用消息更好。
而多大的“模块”算是一个“模块”呢?还得自己把握。   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-15 09:44 |  zaccheo
和楼主的情况差不多,同样有一个新项目的设计。采用的思路类似于楼主的第三种思路:各个模块对外提供接口(模块实现的业务接口);模块内部状态变化,向订阅者发消息。消息使用 googlebuffer 这样很容易从二进制的消息体中反序列化出来消息的结构体。 

基于接口的设计中有一个要注意的问题:接口指针的生命周期管理。如是使用智能指针,是否能避免循环引用的问题? 

看了楼主的分析,我现在倒觉得第二种更好。各个模块间完全被隔离开了。   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-15 10:25 |  Richard Wei
@zaccheo

接口的管理,我感觉有2种方式: 一种是基于COM的引用计数,大家都可以保存接口指针,这里要避免循环引用;还有一种是让Module Manger统一管理,也就是只有Module Manager保存有接口指针,其他模块不保存接口指针,要使用时统一向Module Manger要。

第一种高效,第二种相对安全
最近公司准备开发一个新产品,需要重新设计一套新的框架,但是就这框架中各模块的通信方式,大家产生了争论,主要集中在各模块的交互方式是消息耦合还是接口耦合。

需求大概这样,我们需要封装一套客户端SDK, 暴露一系列API给外部用,而这套SDK内部会有很多模块组成,这些模块之间相互会有交互。

第一种设计是基于接口耦合,框架如下:


这种接口方式的设计要点是:
a. 各模块以类似COM组件的方式封装和暴露接口,也就是说模块会以接口的形式暴露接口,并且以Sink的方式通知外部事件。比如模块A的接口如下
class  IA
{
public :
     virtual  void  fun1() = 0;
     virtual  void  fun2() = 0;
     .
     virtual  void  int  AdviseSink(IASink* pSink) = 0;
     virtual  void  bool  UnAdviseSink( int  nCooki) = 0;
}

class  IASink
{
public :
     virtual  void  Event1() = 0;
     virtual  void  Event2() = 0;
     .
}
b. 有一个统一的模块管理平台来管理所有模块,可以通过该平台查询和加载需要的模块,然后后得到相应的接口指针进行操作。
c. 各模块间的交互全都通过直接调用其他模块的接口或是订阅该模块的Sink来实现。

第二种设计是基于消息耦合,框架如下:

这种消息方式的设计要点是:
a. 各个模块只有一个消息处理接口。 
     class  IMessageHandler
    {
     public :
         virtual  void  ProcessMessage(Message& msg) = 0;
    };
b. 中间的消息总线提供消息的订阅和分发,各个模块会向消息总线注册自己感兴趣的消息。
c. 需要调用某个模块接口 或是 触发某个事件时,都是通过向消息总线发送消息的方式, 然后由订阅消息的模块执行。

上面2种架构的设计方式各有优劣,下面我们来简单比较一下:
(1)耦合性: 尽管基于接口的耦合已经降低了耦合性,但是相比消息来说,显然是消息方式耦合性更弱。
(2)可扩展性: 某个模块新增加一个接口, 接口方式需要新加接口函数,而消息方式只需要新加一个消息类型。即使新增加一个模块,消息方式只是新增加几个消息处理类型,非常方便。所以可扩展性来说,显然也是消息方式占优。
(3)性能: 接口方式是直接调用,可是消息方式需要经过消息总线过滤分发, 显然性能上接口方式更高。 
(4)编码安全性,接口方式是强类型,接口一修改,编译时就能很快发现问题;消息方式却是弱类型,消息修改后,有可能要到运行时才能发现问题, 另外很多消息内容要做强制了类型转换才能使用。
(5)文档要求: 显然接口方式相对比较清晰,消息的话每个消息都要详细定义,并且严格按照该定义执行。
(6)可调试性: 显然接口方式要方便些,消息很可能不小心就会引起混乱。
(7)监控过滤方便性:消息方式走同一总线,可以很方便的增加过滤和监控功能, 接口方式则因为各个模块interface和Sink各不相同,增加这些功能没那么方便。
(8)跨线程或是跨进程,甚至跨机器调用:显然接口方式基本做不到,消息方式的话只要修改总线就可以做到。
(9)异步支持: 消息方式可以很方便的支持异步,接口方式则做不到。

经过上面的比较, 我们可以得出一些结论:
消息方式的强项是耦合性和扩展性,以及监控的方便性,个人感觉比较适合于Server端的大规模应用。
接口方式的强项是性能高效以及开发的方便性, 比较适用于同一进程内客户端的小规模应用。

但是大部分时候, 对于架构师或是公司领导,他们会更关注可耦合性和可扩展性,所以他们会倾向于选择消息方式,尽管有时可能不是那么适用。

另外,个人觉得编译时静态类型检测是C++的优势,能让我们高效而可靠的开发程序,我们不应该放弃这些优势而去把C++当作弱类型的动态语言来使用,我在  软命令接口的适用场合  一文也有相关描述。

最后,对于该框架的设计,其实我个人倾向于上面2种方式的结合, 即各个模块的入接口(调用接口)走接口方式,而各模块内部触发的事件走消息总线的方式,虽然没人采用这种方式,还是在这里记录一下。

一个多月了,消息还是接口,领导们老大们关于走何种架构还在争论中, 我等小兵就默默等待吧 ...

呵呵,不知道各位看客会作何选择?
posted on 2012-10-12 22:50  Richard Wei 阅读(2277)  评论(5)   编辑  收藏  引用 所属分类:  架构体系

FeedBack:
#  re: 消息耦合还是接口耦合[未登录]
2012-10-13 21:58 |  123
反驳下:

多核技术发展到现在,接口比消息性能好显然是说不通的。毕竟消息的方式更有利于并行。
另外,个人觉得接口方式虚函数一大堆,各种继承,也不明白开发能有多方便。

最后关于接口方式的结论,出发点也不明确,既然是“同一进程内客户端的小规模应用”,接口方式也显得太大了,难道是为了模式而模式?   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-13 22:28 |  Richard Wei
@123
我们是客户端应用,各模块内部却确实会有多线程,但是各模块间的调用及事件触发都是跑在主线程里,所以这种情况下,如果走消息,基本上要给每个消息维护一个数组,内部保存哪些人订阅了该消息,当该消息到达时进行依次分发,所以这里无论是内存大小还是性能都会比接口直接调用消耗更多。

接口每个方法都有各自不同的明确的参数定义, 消息的话因为要求所有消息参数一致,所以会导致参数含义不明确,内部保存的指针需要强制转换才能使用。

"客户端小规模应用";是相对“大规模Server集群”, 其实我们要做的东西本身也挺大挺复杂,好几十人同时开发。   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-14 15:56 |  irons
我觉得接口更作为一个模块内的设计,而模块间还是用消息更好。
而多大的“模块”算是一个“模块”呢?还得自己把握。   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-15 09:44 |  zaccheo
和楼主的情况差不多,同样有一个新项目的设计。采用的思路类似于楼主的第三种思路:各个模块对外提供接口(模块实现的业务接口);模块内部状态变化,向订阅者发消息。消息使用 googlebuffer 这样很容易从二进制的消息体中反序列化出来消息的结构体。 

基于接口的设计中有一个要注意的问题:接口指针的生命周期管理。如是使用智能指针,是否能避免循环引用的问题? 

看了楼主的分析,我现在倒觉得第二种更好。各个模块间完全被隔离开了。   回复   更多评论
  
#  re: 消息耦合还是接口耦合
2012-10-15 10:25 |  Richard Wei
@zaccheo

接口的管理,我感觉有2种方式: 一种是基于COM的引用计数,大家都可以保存接口指针,这里要避免循环引用;还有一种是让Module Manger统一管理,也就是只有Module Manager保存有接口指针,其他模块不保存接口指针,要使用时统一向Module Manger要。

第一种高效,第二种相对安全
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
fluent edem耦合接口是将两个软件工具流体动力学软件FLUENT和离散元软件EDEM进行耦合接口。FLUENT是一种用于求解流动和传热问题的计算流体动力学(CFD)软件,而EDEM则是一种用于模拟颗粒运动和固体粒子系统的离散元(DEM)软件。 这个耦合接口的目的是将FLUENT和EDEM两个软件的能力结合起来,以解决颗粒物在流体中的传输和相互作用问题。通过耦合,可以获得更加精确和真实的颗粒流动和传热问题的解决方案。 在FLUENT edem耦合接口中,首先,FLUENT负责处理流动场的模拟,得出速度、压力等流体动力学信息。然后,这些流场信息将被传递到EDEM中,EDEM使用离散元方法对颗粒物进行模拟,并计算颗粒物之间的相互作用。最后,EDEM将计算得到的颗粒物信息(如位置、速度、力等)传递回FLUENT,FLUENT根据这些信息进行流动场的修正,形成一个闭环。 通过FLUENT edem耦合接口,可以模拟颗粒物在流体中的沉积、悬浮、输运、碰撞等行为,并进一步分析颗粒物对流动和传热过程的影响。这对于研究颗粒流动、携带物质的输运和传热、颗粒物的沉积和悬浮等诸多领域具有重要意义,如粉尘在工业生产中的排放与污染控制、颗粒床反应器的设计与优化等。 总之,FLUENT edem耦合接口充分发挥了FLUENT和EDEM两个软件工具的优势,为解决颗粒流动和传热问题提供了一种更为准确和全面的模拟方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值