以 合同 - 产品 - 收入确认 示例来说解领域逻辑模式

业务背景:sql

根据合同类型的不一样,会有不一样的产品,产品的不一样,有不一样的收入方式。已知每一个合同的合同ID,假设产品类型现有的收入确认方式为(s->a),(w->b),(d->c)数据库

(s->a)表示若是产品类型是s,那么收入确认的方式就是a,依次类推,一共有3中产品设计模式

数据库中的三张表: products 、contracts、revenueRecognitionsbash

代码以说清楚为目的,不会完整写下实例,会用参合伪代码网络

事务脚本

使用过程来组织业务逻辑,每一个过程处理来自表现层的单个请求。做者起名由来:通常一个数据库事务对应一个事务脚本架构

  1. 提供一个数据入口,来查找合同与对应的产品
public ResultSet findContract(long contractId){

 	//将sql 查到的数据集返回 select * from contracts c , products p where id = contractId and c.product = p.id
 } 
复制代码
  1. 领域层拿到对应的合同以后,而后按照合同的收入确认逻辑直接组织
public void calculateRevenueRecognitions(long contractId){

	ResultSet controcts = findContract(contractId);
	String productType = controcts.get("productType");
	if( "s".equals(productType) ){
		//执行 a 收入确认逻辑代码块
	}else if( "w".equals(productType) ){
		//执行 b 收入确认逻辑代码块
	}else if( "d".equals(productType) ){
		//执行 c 收入确认逻辑代码块
	}  
}

复制代码

运行机制

在事务脚本中,领域逻辑主要由组织系统所执行的事务来组织。代码结构自己能够以合理的方式模块化。对于多个事务脚本经常使用的组织方式是:模块化

  • 每一个类围绕一个主题将相关的事务脚本放在一块儿
  • 每一个事务脚本就是一个类,使用 命令模式 来实现

使用时机

少许逻辑的程序来说,这种实现方式很天然,开发很快,性能以及后期维护理解开销都不大,可是若是业务复杂起来,因为事务脚本自己主要是为了处理一个事务,那么任何公共代码均可能存在多个副本,谨慎的提取公共模块能够解决问题,但再往复杂了去,要更好的组织代码,组织公共模块,须要领域模型性能

领域模型

合并行为和数据的领域的对象模型ui

  1. 产品的领域模型负责作不一样产品的确认方式
class Product{

	private StrategyParent strategy;

	public static Product newS(){
		return new Product(new AStrategy());
	}

	public static Product newW(){
		return new Product(new BStrategy());
	}

	public static Product newD(){
		return new Product(new CStrategy());
	}

	public void calculateRevenueRecognitions(Contract contract){
		strategy.calculateRevenueRecognitions(contract);
	}
}
复制代码
  1. 每一个策略抽象出来了公共的父类 StrategyParent ,以及对应策略的实现类 AStrategy、BStrategy、CStrategy,这样就能够以插件的形式随时增长不一样的策略就能够影响收入确认的方式this

  2. 在合同里面计算收入产品的收入确认

class Contract{
	private Product product;

	//会有构造方法来传入合同

	public void calculateRecognitions(){
		product.calculateRevenueRecognitions(this);
	}
}
复制代码
  1. 使用领域模型
class Test{

	public static void main(String[] args){
		Product s = Product.newS();
		Contract c=new Contract(s);
		c.calculateRevenueRecognitions();
	}
}
复制代码

运行机制

创建一个完整的由对象组成的层,对目标业务进行领域建模,经过类之间的交互,来完成任务。他有两种风格

  1. 几乎每个数据库表都对应一个对象,和数据库表相似,能够直接让领域对象自己去存储数据
  2. 使用继承、策略和其它设计模式,有多个互联的细粒度对象组成的复杂网络,须要数据映射器

对象之间的连续传递,自己就把处理逻辑递交给了“有资格”处理这件事情的对象,自身的调用链就是逻辑链,消除了不少条件判断,也提高了内聚,减小了不一样对象之间的耦合。只是在阅读的时候须要不停的跳转不一样的类来查看逻辑,并且一个领域自己有可能因为自身的业务过多而过于臃肿(实际中臃肿发生几率偏低,建议不要由于臃肿而强行分离,高出一段特殊处理的代码,而产生冗余逻辑,而应该先放到原本就应该在的对象中)

使用时机

若是业务规则复杂多变,涉及校验、计算、衍生应该用对象模型处理,反之只是作空值判断和少许求和计算,事务脚本是个更好的选择

表模块

以一个类对应数据库中的一个表来组织领域逻辑,并且使用单一的类实例包含将对数据进行的各类操做程序。表模块提供了明确的基于方法的接口对数据进行操做

  1. 从表中获取数据将数据记录到数据集 DataSet 中它相似于数据库结构

  2. 每个表模块 TableModule 都拥有数据集中的一个表 DataTable

class TableModule{
	protected DataTable table;
	protected TableModule(DataSet ds,String tableName){
		table = ds.Tables[tableName];
	}
}

复制代码
  1. 子类能够继承表模块,同时每一个表模块类(子类也是一个)均可以拥有操做 DataTable 的能力
class Contract extends TableModule{
	public Contract(DataSet ds){
		super(ds,"contracts");
	}
	public DataRow thisRowById(long primaryKey){
		return table.select("ID = "+primaryKey)[0];
	}
}
复制代码
  1. 经过多个表模块的行为来一块儿完成实际的收入确认工做
class  Contract {
	//...

	public void calculateRecognitions(long contractId){
		DataRow contractRow = thisRowById(contractId);

		//多个表模块公用一个数据集
		Product prod = new Product(table.DataSet);

		//从合同表模块中拿到对应的合同产品数据
		long prodId = GetProductId(contractId);

		//从产品表模块获取产品的数据类型
		String productType = prod.getProductType(prodId);

		//执行计算逻辑,逻辑中凡是涉及到须要操做数据的操做,也是经过表模块来完成
		if( "s".equals(productType) ){
		//执行 a 收入确认逻辑代码块
		}else if( "w".equals(productType) ){
			//执行 b 收入确认逻辑代码块
		}else if( "d".equals(productType) ){
			//执行 c 收入确认逻辑代码块
		}
	}
}
复制代码
  1. 数据集的逻辑处理并校验正常以后,就能够存入数据库了

运行机制

表模块将数据与行为封装在一块儿,它能够是一个实例,也能够是一个静态方法的集合。典型的流程是,应用程序首先将数据聚集到一个记录集中,使用该记录集建立一个表模块,若是有多个表模块行为,则一块儿建立,这样表模块就能够在记录集上应用业务逻辑,而后将修改后的记录集传给表现层,表现层处理完后,数据集给表模块校验,并相应存入数据库

与常规对象的关键区别在于它自己没有标识符来表示它所表明的实体对象,一般须要数据库的主键值来查询对应的数据,好比 prodTableModule.getProductType(prodId)

使用时机

表模块依赖于以表的形式组织数据,适合于使用记录集存取表数据的状况,可是表模块没有提供面向对象能力来组织复杂的领域逻辑,不能在实例之间创建联系

服务层

经过一个服务层来定义应用程序边界,在服务层中创建一组可用的操做集合,并在每一个操做内部协调应用程序的响应

  • 提供一个收入确认服务 RecognitionService来组织业务逻辑,具体的事情交给领域对象 Contract 去完成
public class ReconitionService{
	public void calculateRevenueRecognitions(long contractNumber){
		Contract contract = Contract.readForUpdate(contractNumber);
		contract.calculateRevenueRecognitions();
	}
}
复制代码

运行机制

对于较大的应用,经过垂直企鹅人软件结构将它分红若干个“子系统”,每一个子系统包含切出来的一个部分,每一个子系统能够用该子系统名字来命名,可选的方案包括按照领域模型来划分 ContractService,ProductService 或者是按照程序行为主题来划分 ReconitionService

使用时机

若是业务逻辑只有一种或者响应不涉及多个事务性资源,就可能不须要服务层,可是只要有多种或多个事务性质资源,则有必要一开始就设计服务层

附录

<企业应用架构模式> 第九章

相关文章
相关标签/搜索