基本模式

  • Layer Supertype层超类型
    • 某一类型充当一层中所有类型的超类型.(DomainObject).
    • 运行机制
      • 当软件某一层中所有对象有公共特征时,可以将这些特征提取到一个超类上去.
  • Separated Interface分离接口
    • 在一个包中定义接口,而在另一个与之分离的保重实现该接口.
      • 为了减少系统部件间的耦合,将类分组,然后组织成包,并限制包间的依赖关系.同时约定包间调用的约束.
      • 但是,可能会出现与包间通用的一般性依赖关系有冲突的调用关系.
      • 此时,使用分离接口.一个包中定义接口,而在另一个包中实现它.
      • 分离接口为入口提供了一个很好的插入点.
    • 运行机制
      • 实现类对接口存在依赖,反之没有.
      • 所以,实现包到接口包有依赖.其它包仅依赖于接口包,而忽略掉实现包.
      • 当然,还是需要将接口和实现连接起来
        • 可以在编译时使用另一个独立的包来完成.
        • 或者在软件配置时使用插件模式.
      • 接口的放置位置
        • 当只有一个客户,或者所有客户都在同一包中.则可以将接口放在客户包中.由客户负责定义接口.
        • 若有多个客户包,则定义一个第三方的接口包比较好.或者需要有实现包来定义接口规范时.
    • 使用时机
      • 需要打破两个部分之间的依赖时
        • 一层需要调用另一层的代码,但是调用者却不知道被调用者的存在.如领域层调用数据映射层.
        • 需要调用别人的函数,但是不想与他们提供的API产生依赖.
        • 框架包中包含了一些通常情况的抽象代码,而框架包需要调用一些特定应用代码.
      • 该模式的依赖管理过于复杂
        • 对于小系统,在创建对象时与实现类建立依赖,而后只使用接口就可以了.
        • 保持接口和实现的分离需要额外的工作.一般还需要创建接口和实现的工程类.
        • 只有当需要打破依赖关系,或者同一接口有多个独立的实现时,才需要使用分离接口.
        • 一般吧实现和接口放在一起,将来需要时在重构即可.
  • Registry注册表
    • 一个well-known对象,其他对象通过它可以找到公共的对象和服务.
      • 在定位某一对象时,需要从管理对象入手.当没有合适的初始对象时,需要某种查找方法.
    • 运行机制
      • 在注册表接口中使用静态方法.
        • 方便其他类查找.
      • 数据的保存,应首先考虑数据的作用域
        • 不同作用域要求不同的实现,但是有一致的接口.
        • 进程.
          • 可以使用静态域.
          • 但是静态域的问题是不可替换性.
          • 也可以考虑Singleton.但是这样的问题在于多线程时的复杂同步代码.
        • 线程.使用词典.以线程为键,值为线程的数据对象.
        • 会话.使用词典.
      • 分割
        • 以使用方式而非实现来分割.可以有N个Registry.
    • 使用时机
      • Registry本质上是一个全局数据.
      • 一般使用常规的对象间引用来访问对象.有多种替代方案
        • 通过参数传递常用数据.问题是会在N层中出现无谓的参数传递开销.
        • 在对象创建时把指向公共数据的引用传递给它.当数据只被部分类使用时比较合适.
      • 每当增加新类型的数据时,都需要更新Registry.
      • 好处是显示的方法接口.
        • 使用映射存储全局数据,是隐式的.
  • Value Object值对象
    • 一个如货币/日期范围这样的小而简单的对象,判等时并不根据其ID.
      • 类似于原始类型.
    • 运行机制
      • 值对象是小对象,引用对象是大对象.
      • 关键区别还是判等方法.引用对象基于标识.值对象基于类内部的属性值.
      • 值对象小且易于创建,作为参数传递时传值而不是引用.
      • 值对象应作为嵌入值/序列化LOB,而非完整记录来进行持久化.
    • 使用时机.
      • 判等不基于标识.小且易于创建.
  • Special Case特殊情况
    •  
    • 针对特殊情况提供特殊行为的子类
      • 空值.破坏多态性.必须在可能为空的环境中加入判断.如果多个地方有相似的判空逻辑,造成了冗余代码.
      • 数字中的"无限"....
      • 处理:返回一个特殊情况.它具有与调用者预期相同的接口.而非返回空值或某个奇怪的值.
    • 运行机制
      • 创建一个特殊情况子类,重置所有的方法,提供一些无害的行为.
      • 通常不需要区分是否是特殊情况(是否是空客户).
      • NaN就是特殊情况的实例.
    • 使用时机
      • 当很多地方都需要对某一特定类的实例进行条件检测,然后做相同的动作时.
  • Plugin插件
    • 在配置时而非编译时进行类链接.
      • 代码需要在多个环境中运行,且每个环境下对特定行为需要不同的实现时.通常会使用分离接口模式.
      • 之后,工厂方法负责在特定环境下返回需要的实现.
      • 当工厂数目变多时,难以维护以后的变更.
      • 插件模式通过提供集中化的,运行时配置来解决.
    • 运行机制
      • 首先,通过分离接口来定义那些在不同环境下有不同实现的行为.
      • 然后使用基本工厂模式.
      • 特定环境下,接口与那个实现连接的指定需要在一个单独的,代码之外的地方进行声明,以获取可管理性.
        • txt即可很好的描述链接规则.
        • 插件工厂只是简单滴读取txt,来查找当前环境下所需接口对应哪一个具体实现项,然后返回该相应实现.
      • 与实现的链接必须在运行时动态进行,这样在重新配置后无需重新编译.
        • 配合反射机制.工厂可以动态地构建实现对象.
        • 配置文件必须包含从接口名到实现类型的映射.
    • 使用时机
      • 行为在不同运行环境下要求不同的实现时,应该使用插件模式.
  • Service Stub服务桩
    • 在测试时移出对有问题的服务的依赖.
      • 对于第三方的服务.在开发阶段.使用真实的服务来进行测试是很难实现的(远程的,耗时的...)
      • 在测试时,用运行在本地的,快速的,位于内存中的服务桩来代替第三方服务来推进开发进度.
    • 运行机制
      • 首先,使用入口来定义一个服务的访问点.入口应该是一个分离接口.
      • 然后,针对该入口接口,有一个调用实际服务的实现(发布时),和一个服务桩的实现(测试时).
      • 所需的入口实现以插件的方式载入.
      • 服务桩的关键在于简单.
      • 也就是单元测试中的Mock Object.模拟对象.
  • Record Set记录集
    • 表格数据在内存中的表现形式.
      • 看起来像数据库查询的结果.但是可以在其上附加业务逻辑部件.
      • 能够断开记录集与其数据源链接的能力.可以序列化记录集,从而将其作为DTO来传输.
      • 可以当做工作单元的一种形式.对其中数据的更新,可以使用乐观离线锁来检测是否存在冲突,没有冲突时将数据回写到DB中.
原文地址:https://www.cnblogs.com/robyn/p/3529573.html