框架设计原则

介绍

好的架构和设计可以增加系统健壮性同时也便于维护。面向对象的设计过程中,需要先进行泛化,抽象。然后对具体的对象进行窄化,细化。

了解框架设计思想不但可以开阔思维,增加阅读开源项目源码的能力。更能提升一个程序员对程序的抽象和管理能力。

以下设计理念来源于Dubbo作者梁飞的总结,很有参考学习意义。总结整理以供学习

大纲

  • 模块分包原则
  • 框架扩展原则
  • 领域划分原则
  • 接口分离原则
  • 组件协作原则
  • 功能演进原则
模块分包原则

对业务进行抽象建模,业务数据与业务逻辑解耦,平台和产品解耦,系统各部件解耦。模块、组件高内聚,低耦合。

稳定度:各模块被依赖的包应该保持稳定,或者说,被依赖者应当比依赖者稳定,且不能成环状依赖。如果不稳定,将会影响其他的包。

抽象度,越抽象,越稳定。越具体,越容易变化。

框架扩展原则

微核插件式,平等对待第三方。
比如Eclipse的微核是OSGi, Spring的微核是BeanFactory,Maven的微核是Plexus,通常核心是不应该带有功能性的,而是一个生命周期和集成容器,这样各功能可以通过相同的方式交互及扩展,并且任何功能都可以被替换, 如果做不到微核,至少要平等对待第三方。

外置生命周期,尽量引用外部对象的实例,而不类元。尽量使用IOC注入,减少静态工厂方法调用
也就是说,框架只负责管理对象,对象的出生和死亡不由框架负责。即,用户应将实例注册到框架中。
以服务、数据为中心,构建服务化、组件化架构,具备灵活,按需组合的能力。
但Spring就是负责管理对象的生命周期的框架,这个我认为还是在于框架对于自身的定位问题。要灵活对待。

最少化概念模型,这个其实是一种优化,保持尽可能少的概念,有助于理解。另外,各接口都使用一致的概念模型,能相互指引,并减少模型转换 。

一致化数据模型:例如 URL 这种对象,就是一致化数据模型,拒绝使用 String 拼接,解析。

领域划分原则

任何框架或组件,总会有核心领域模型,比如: Spring的Bean,Struts的Action,Dubbo的Service等等。
这个核心领域模型及其组成部分称为实体域,它代表着我们要操作的目标本身,实体域通常是线程安的,不管是通过不变类,同步状态,或复制的方式。
服务域也就是行为域,它是组件的功能集,同时也负责实体域和会话域的生命周期管理,比如Spring的ApplicationContext,Dubbo的ServiceManager等。

领域模型划分优势:

  • 结构清晰,可直接套用
  • 充血模型,实体域带行为。
  • 可变与不可变状态分离,可变状态集中
  • 所有领域线程安全,不需要加锁

只有保证领域模型线程安全性设计,可变和不可变状态分离,可变状态集中。才能实现无锁编程。同时,设计一定要轻量。否则,对 GC 来说,将是很大的压力。

通常实体域都是只读的,即不变状态。会话域都是可变状态。

服务域无状态,天生线程安全,只需单一实例运行。
实体域属性只读,或整个类应用替换,线程安全。
会话域只在线程栈中使用,没有竞争,线程安全。

接口分离原则

  • 接口分离,单一职责原则的实现。
  • API 面向用户,SPI 面向开发者。两者必须分离。
  • 声明式 API 和过程式 SPI
  • API 可配置,一定可编程
  • 区分命令和查询,例如,不应该有 updateAndGet 这个方法(不包括原子类),应该分成 2 个方法,保证 get 方法幂等。
  • 对称性接口:有 get 方法,就应该有 set 方法,有 add 就由 remove,称之为对称性和完备性。这样用户能自行推导出接口。
  • 兼容性:如果接口加方法,应该是增加子接口的方式。
组件协作原则

首先Dubbo 是管道式设计。一个 Invoker 贯通整个流程,比如Netty的EventLoop、pipeline

关于派发,比如Spring 的 dispatchServlet

Dubbo 暴露、引用、调用事件,都预留了监听器。

关键路径,即在管道使用责任连模式进行拦截,保证每个拦截器职责单一。

非关键路径,采用后置事件派发,不能影响主流程运行。

防御性编程。

  • 防止空指针和下标越界,我认为这类问题是最不应该出现的,每敲一行代码都要考虑到
  • 保证线程安全性和可见性,防止高并发下出现莫名其妙的问题
  • 尽早失败和前置断言,这样报错后,其实内部状态可能已经混乱
  • 分离可靠操作和不可靠操作,比如,写入一个线程安全的Map,可以认为是可靠的,而写入数据库等,可以认为是不可靠的,不可靠操作要增加容错
  • 异常防御,但不忽略异常
  • 缩小可变域和尽量final
  • 降低修改时的误解性,不埋雷 一个原则就是永远不要区分null引用和empty值。
  • 提高代码的可测性
功能演进原则

  • 开闭原则,微核心加插件机制。 软件质量的下降,来源于修改。
  • 每个扩展点只封装一个变化因子,最大化复用。
  • 全管道式设计,框架自身逻辑,均使用截面拦截实现。
  • 加功能的姿势:应该是增量式,而不是扩充式,即不在原有基础上修改,而是新增加功能。
  • 关于高阶:顶层接口尽量抽象,且不能依赖底层实现。这样,当底层实现变化时,高层无需变化。

总结

参考:http://javatar.iteye.com/blog/706098

------本文结束感谢阅读------
显示评论
0%