業務背景:sql
根據合同類型的不一樣,會有不一樣的產品,產品的不一樣,有不一樣的收入方式。已知每一個合同的合同ID,假設產品類型現有的收入確認方式爲(s->a),(w->b),(d->c)數據庫
(s->a)表示若是產品類型是s,那麼收入確認的方式就是a,依次類推,一共有3中產品設計模式
數據庫中的三張表: products 、contracts、revenueRecognitionsbash
代碼以說清楚爲目的,不會完整寫下實例,會用參合僞代碼網絡
使用過程來組織業務邏輯,每一個過程處理來自表現層的單個請求。做者起名由來:通常一個數據庫事務對應一個事務腳本架構
public ResultSet findContract(long contractId){
//將sql 查到的數據集返回 select * from contracts c , products p where id = contractId and c.product = p.id
}
複製代碼
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
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);
}
}
複製代碼
每一個策略抽象出來了公共的父類 StrategyParent ,以及對應策略的實現類 AStrategy、BStrategy、CStrategy,這樣就能夠以插件的形式隨時增長不一樣的策略就能夠影響收入確認的方式this
在合同裏面計算收入產品的收入確認
class Contract{
private Product product;
//會有構造方法來傳入合同
public void calculateRecognitions(){
product.calculateRevenueRecognitions(this);
}
}
複製代碼
class Test{
public static void main(String[] args){
Product s = Product.newS();
Contract c=new Contract(s);
c.calculateRevenueRecognitions();
}
}
複製代碼
創建一個完整的由對象組成的層,對目標業務進行領域建模,經過類之間的交互,來完成任務。他有兩種風格
對象之間的連續傳遞,自己就把處理邏輯遞交給了「有資格」處理這件事情的對象,自身的調用鏈就是邏輯鏈,消除了不少條件判斷,也提高了內聚,減小了不一樣對象之間的耦合。只是在閱讀的時候須要不停的跳轉不一樣的類來查看邏輯,並且一個領域自己有可能因爲自身的業務過多而過於臃腫(實際中臃腫發生機率偏低,建議不要由於臃腫而強行分離,高出一段特殊處理的代碼,而產生冗餘邏輯,而應該先放到原本就應該在的對象中)
若是業務規則複雜多變,涉及校驗、計算、衍生應該用對象模型處理,反之只是作空值判斷和少許求和計算,事務腳本是個更好的選擇
以一個類對應數據庫中的一個表來組織領域邏輯,並且使用單一的類實例包含將對數據進行的各類操做程序。表模塊提供了明確的基於方法的接口對數據進行操做
從表中獲取數據將數據記錄到數據集 DataSet 中它相似於數據庫結構
每個表模塊 TableModule 都擁有數據集中的一個表 DataTable
class TableModule{
protected DataTable table;
protected TableModule(DataSet ds,String tableName){
table = ds.Tables[tableName];
}
}
複製代碼
class Contract extends TableModule{
public Contract(DataSet ds){
super(ds,"contracts");
}
public DataRow thisRowById(long primaryKey){
return table.select("ID = "+primaryKey)[0];
}
}
複製代碼
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 收入確認邏輯代碼塊
}
}
}
複製代碼
表模塊將數據與行爲封裝在一塊兒,它能夠是一個實例,也能夠是一個靜態方法的集合。典型的流程是,應用程序首先將數據聚集到一個記錄集中,使用該記錄集建立一個表模塊,若是有多個表模塊行爲,則一塊兒建立,這樣表模塊就能夠在記錄集上應用業務邏輯,而後將修改後的記錄集傳給表現層,表現層處理完後,數據集給表模塊校驗,並相應存入數據庫
與常規對象的關鍵區別在於它自己沒有標識符來表示它所表明的實體對象,一般須要數據庫的主鍵值來查詢對應的數據,好比 prodTableModule.getProductType(prodId)
表模塊依賴於以表的形式組織數據,適合於使用記錄集存取表數據的狀況,可是表模塊沒有提供面向對象能力來組織複雜的領域邏輯,不能在實例之間創建聯繫
經過一個服務層來定義應用程序邊界,在服務層中創建一組可用的操做集合,並在每一個操做內部協調應用程序的響應
public class ReconitionService{
public void calculateRevenueRecognitions(long contractNumber){
Contract contract = Contract.readForUpdate(contractNumber);
contract.calculateRevenueRecognitions();
}
}
複製代碼
對於較大的應用,經過垂直企鵝人軟件結構將它分紅若干個「子系統」,每一個子系統包含切出來的一個部分,每一個子系統能夠用該子系統名字來命名,可選的方案包括按照領域模型來劃分 ContractService,ProductService 或者是按照程序行爲主題來劃分 ReconitionService
若是業務邏輯只有一種或者響應不涉及多個事務性資源,就可能不須要服務層,可是隻要有多種或多個事務性質資源,則有必要一開始就設計服務層
<企業應用架構模式> 第九章