閱讀目錄:
坊子ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!
1.開篇介紹
2.程序書簽(代碼書簽機制)
2.1ProgramBookmark 實現(xiàn)(使用委托來錨點代碼書簽)
2.2ProgramBookmarkManager書簽管理器(對象化書簽集合的處理,IEnumerable<T>書簽管理)
3.可恢復語句組件(將語句對象化)
3.1可恢復語句組件管理器(將可恢復語句視為普通的對象成員,IEnumerable<T>可恢復語句組件)
3.2可恢復語句組件運行時(Program CLR(簡介))
3.3可恢復語句邏輯配置(規(guī)則的配置(簡介))
3.4可恢復語句邏輯傳輸(將邏輯語句對象遠程傳輸(簡介))
4.DomainModel規(guī)則引擎(規(guī)則持久化后管理配置(簡介))
這一篇文章我早準備寫的,遲遲未寫的原因是它過于抽象不太容易表達,也很難掌握;之前對它的理解還處于比較簡單的功能性上,但是最近隨著對領(lǐng)域驅(qū)動設(shè)計及架構(gòu)的研究,設(shè)計思想有了一個提升對它的理解也有了一個更清晰的輪廓,所以才敢下手去寫,這么好的一篇文章不能搞砸了;
“鈍化語句”簡單描述:將基于棧的調(diào)用抽象成基于我們自己構(gòu)建的虛擬運行時調(diào)用;
比如我們可以將普通的IF\ELSE調(diào)用進行對象化,然后就可以對他們進行面向?qū)ο蟮脑O(shè)計了;能做的事情就太多了,比如將所有的方法放入一個for循環(huán)語句組件當中去,它會自動的去循環(huán)執(zhí)行,而不需要我們再去自己寫for語句;然后在此基礎(chǔ)上進行代碼書簽抽象對所有的代碼片段進行類似邏輯錨點的設(shè)定;
更嚇人的是可以瞬間將語句組件鈍化,其實也就是瞬間凍結(jié)然后持久化,在遙遠的地方再將它喚醒執(zhí)行,很可能你的語句在你這臺電腦上執(zhí)行了一半由于你臨時有事然后語句被鈍化,在另外一臺電腦上繼續(xù)你的工作,是不是很方便;當然它的使用方式多種多樣了;
我相信這篇文章絕對讓你對 .NET框架設(shè)計 感興趣,框架設(shè)計思想其實真的很美,讓人陶醉;
美好的一切都要有一個良性的開始,程序的鈍化少不了對程序的邏輯保存的功能;有一個連續(xù)的調(diào)用穿過N個方法,方法一調(diào)用方法二,方法二調(diào)用方法三,這樣的調(diào)用層次是根據(jù)業(yè)務(wù)的需求來定的,就好比一個復雜的業(yè)務(wù)邏輯這樣的處理下去合情合理;
那么什么是代碼書簽呢?其實我們仔細分析一下我們?nèi)粘K鶎懙拇a基本上都是由方法組合而成,不管是實例類還是靜態(tài)類都是通過方法將彼此聯(lián)系起來,所有的業(yè)務(wù)邏輯都是包裝在方法的內(nèi)部處理的,這里的代碼書簽就是方法的可持久化抽象;
試想一下,我們要想將程序的邏輯流程鈍化肯定是少不了對邏輯調(diào)用的保存;原本的程序邏輯是線程本地的執(zhí)行路徑,屬于.NETCLR直接管理的,依賴于棧的執(zhí)行,所以我們無法干預其生命周期過程,那么我們只有將它們對象化后才能由我們自己操控;
圖1:
上圖的意思是說在一個流程的開始到結(jié)束基本上三個重要環(huán)節(jié),Begin\Processs…\End過程,在每個過程中需要不同的處理邏輯,在圖的偏上方,我們有三個ProcessName名稱的小方塊表示程序的調(diào)用順序,ProcessName1調(diào)用ProcessName2調(diào)用ProcessName3;
在ProcessName2的上面我們加了一個Bookmark的標記,表示我們這里所說的代碼書簽,通過代碼書簽我們就可以記錄下本次執(zhí)行到哪里了,就好比我們在看書的時候都有一個買書時贈送的書簽卡,我們看到哪里就把這個書簽卡插在那里,當下次要看的時候直接找到這個書簽卡繼續(xù)看;
這里的代碼書簽跟這個是一樣的道理,理論就是這些我們下面通過示例代碼來親身體驗一下這種設(shè)計模式;
委托是天生的方法標簽,通過委托我們完全可以將一個實例的方法直接錨定下來;
【有關(guān)對委托的高級應(yīng)用不太清楚的可以參見本人的這兩篇文章:
.NET框架設(shè)計(一:常被忽視的C#設(shè)計技巧)、.NET框架設(shè)計(二:常被忽視的框架設(shè)計技巧)】
我們來構(gòu)造代碼書簽對象:
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ namespace ProgramComponent { using System; /// <summary> /// Program book mark. /// </summary> [Serializable] public class ProgramBookmark { /// <summary> /// Mark program book mark. /// </summary> /// <param name="name">Mark name.</param> /// <param name="continueAt">Program continue.</param> public ProgramBookmark(string name, ProgramBookmarkLocation continueAt) { this.markname = name; this.continueAt = continueAt; } private string markname; /// <summary> /// Book mark name. /// </summary> public string BookmarkName { get { return markname; } } private ProgramBookmarkLocation continueAt; /// <summary> /// Continue location. /// </summary> public ProgramBookmarkLocation ContinueAt { get { return continueAt; } } /// <summary> /// Program load data. /// </summary> public object Payload { get; set; } } /// <summary> /// Program book mark location. /// </summary> /// <param name="resumed">Resumed bookmark.</param> public delegate void ProgramBookmarkLocation(ProgramBookmark resumed); }
這段代碼是對代碼書簽的抽象,構(gòu)造函數(shù)傳入一個代碼書簽的名稱、書簽所表示的物理代碼錨點,Payload是表示每次執(zhí)行物理代碼時的輸入?yún)?shù);
上面代碼看似簡單其實很不簡單,它的背后隱藏著一個很大的設(shè)計思想:
將一塊很大的邏輯代碼拆成很多零碎的方法片段,很多人可能會覺得設(shè)計本身不就這樣要求的嘛,那你可能真的沒有深入理解代碼碎片會后需要對所有的方法參數(shù)進行對象化,不管什么方法都會是同樣的參數(shù),只有這樣才能讓書簽連續(xù)起作用;
下面我們來看一下代碼書簽有多巧妙,我們來構(gòu)造一個簡單的示例代碼,當然你完全可以設(shè)計的很復雜很強大,這里畢竟是傳遞這種設(shè)計思想為主;
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { [Serializable] public class OrderCheckFlows { private IList<ProgramComponent.ProgramBookmark> flowsManager = new List<ProgramComponent.ProgramBookmark>(); public OrderCheckFlows() { ProgramComponent.ProgramBookmark bookmarkCheckOrderPrices = new ProgramComponent.ProgramBookmark("checkPrices", new ProgramComponent.ProgramBookmarkLocation(CheckOrderPrices)); flowsManager.Add(bookmarkCheckOrderPrices); } public void StartCheck() { do { flowsManager[0].ContinueAt(flowsManager[0]); } while (flowsManager.Count > 0); } #region business flows public void CheckOrderPrices(ProgramComponent.ProgramBookmark nextCheck) { Console.WriteLine("checkPrices..."); ProgramComponent.ProgramBookmark bookmarkCheckOrderPrices = new ProgramComponent.ProgramBookmark("checkPrices", new ProgramComponent.ProgramBookmarkLocation(CheckOrderItems)); bookmarkCheckOrderPrices.Payload = true;//method parameters. flowsManager.Add(bookmarkCheckOrderPrices); flowsManager.RemoveAt(0); } public void CheckOrderItems(ProgramComponent.ProgramBookmark nextCheck) { if ((bool)nextCheck.Payload) { Console.WriteLine("checkItems..."); } else { Console.WriteLine("end check items."); } flowsManager.RemoveAt(0); } #endregion } }
這個類是一個簡單的模擬檢查訂單的一系列的業(yè)務(wù)流程;
圖2:
上圖能看見流程順利執(zhí)行完畢了,那么我們來解釋一下重要的代碼片段;
圖3:
在第一個流程里面我們構(gòu)造一個通往下一個流程的 ProgramComponent.ProgramBookmark 對象,如果這里出現(xiàn)關(guān)于流程無法繼續(xù)下去的條件就可以不創(chuàng)建往下執(zhí)行的代碼書簽;在第二流程里面我們獲取第一個流程設(shè)置的參數(shù),這里是一個Bool值,可以用來判斷上一個執(zhí)行是否成功等信息;
上一節(jié)我們完成了對代碼書簽的抽象實現(xiàn),但是代碼還有很多值得抽象設(shè)計的地方,上面的代碼中最不太理解的地方就是對書簽集合的操作上,很不OO;
那么這一節(jié)我們將把它改進,形成OO方式的調(diào)用,先看一下哪里不太理解;
圖4:
第一個地方就是在聲明ProgramCompoent.ProgramBookmark集合上,這樣寫問題太大了,無法進行擴展改進;然后就是在構(gòu)造函數(shù)中,我們使用了很長一段代碼來構(gòu)造一個ProgramCompoent.ProgramBookmark對象,完全可以減少很多;還有就是在StartCheck方法的內(nèi)部中進行循環(huán)調(diào)用書簽的代碼,也很有問題,完全可以封裝在內(nèi)部實現(xiàn),外部直接一個CurrentProgram屬性執(zhí)行就行了;
那么對這些問題我們其實少一個ProgramCompoent.ProgramBookmark的管理器對象ProgramCompoent.ProgramBookmarkManager對象,它負責管理所有跟ProgramCompoent.ProgramBookmark對象相關(guān)的工作;
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ namespace ProgramComponent { using System.Collections.Generic; /// <summary> /// Program book mark Manager.<see cref="System.Collections.Dictionary{BookmarkName,ProgramBookmark}"/> /// </summary> public class ProgramBookmarkManager : Dictionary<string, ProgramBookmark> { /// <summary> /// Add programbookmark and instant next programbookmark. /// </summary> /// <param name="bookmark"><see cref="ProgramComponent.ProgramBookmark"/></param> public void Add(ProgramBookmark bookmark) { base.Add(bookmark.BookmarkName, bookmark); } /// <summary> /// Remove programbookmark. /// </summary> /// <param name="bookmark"><see cref="ProgramComponent.ProgramBookmark"/></param> public void Remove(ProgramBookmark bookmark) { base.Remove(bookmark.BookmarkName); } /// <summary> /// Resume bookmark by bookmarkname. /// </summary> /// <param name="bookmarkName">bookmark name.</param> /// <param name="payload">Continue load.</param> public void Resume(string bookmarkName, object payload) { ProgramBookmark bookmark; this.TryGetValue(bookmarkName, out bookmark); if (bookmark != null) { bookmark.Payload = payload; bookmark.ContinueAt(bookmark); } } } }
書簽管理器基本功能還算簡單,主要的方法Resume是用來恢復指定的書簽的;再來看一下訂單檢查流程調(diào)用;
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ namespace ConsoleApplication1 { using System; using ProgramComponent; [Serializable] public class OrderCheckFlows { private ProgramBookmarkManager BookmarkManager = new ProgramBookmarkManager(); public OrderCheckFlows() { BookmarkManager.Add(new ProgramBookmark("checkPrices", new ProgramBookmarkLocation(CheckOrderPrices))); } public void StartCheck() { BookmarkManager.Resume("checkPrices", null); } #region business flows public void CheckOrderPrices(ProgramComponent.ProgramBookmark nextCheck) { Console.WriteLine("checkPrices..."); BookmarkManager.Remove(nextCheck); BookmarkManager.Add(new ProgramBookmark("checkItems", new ProgramBookmarkLocation(CheckOrderItems))); BookmarkManager.Resume("checkItems", true); } public void CheckOrderItems(ProgramComponent.ProgramBookmark nextCheck) { if ((bool)nextCheck.Payload) Console.WriteLine("checkItems..."); else Console.WriteLine("end check items."); BookmarkManager.Remove(nextCheck); } #endregion } }
是不是比之前的代碼好多了,我感覺是好多了,當然還有很大的重構(gòu)空間;
這里其實已經(jīng)可以和鏈式編程的機制掛鉤了,我們可以通過給書簽管理器添加N個擴展方法來使書簽管理器具有跟鏈式的調(diào)用;
要想把所有的調(diào)用都拆開來使用松散的方式組合,通過使用書簽機制基本上能將所有的方法進行松散組合;那么我們還需要將邏輯語法進行對象化才能做到無死角的松散;
什么叫語句組件,就是將一些原本無法獨立的一些邏輯判斷、循環(huán)之類的語句對象化,形成更具有對象的組件;
試想一下,如果我們將所有的這些邏輯語法對象化后我們的代碼中還有精密耦合的代碼嗎?就算有也應(yīng)該會很少,是不是很神奇;
其實對 企業(yè)應(yīng)用架構(gòu) 中的 規(guī)約模式 有所了解的人應(yīng)該會比較熟悉這一節(jié)的內(nèi)容,跟規(guī)約模式很像,但不是一個東西,側(cè)重點不同;語句組件全面的概念是將所有的調(diào)用都對象化,包括一些輸出、輸入、網(wǎng)絡(luò)調(diào)用等等,這樣才是全部的語句組件定義,還記得我們上面的訂單檢查對象嘛,那個也是語句組件之一;
我們來構(gòu)造可恢復語句組件對象;
ProgramComponent.LanguageComponent.LanguageComponent類代碼:
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ namespace ProgramComponent.LanguageComponent { using System; [Serializable] public abstract class LanguageComponent { public abstract void Run(ProgramBookmarkManager mgr); } }
ProgramComponent.LanguageComponent.LanguageComponentBlock類代碼:
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ namespace ProgramComponent.LanguageComponent { using System.Collections.Generic; public class LanguageComponentBlock : LanguageComponent { List<LanguageComponent> statements = new List<LanguageComponent>(); public List<LanguageComponent> Statements { get { return statements; } } public void AddLangugateComponent(LanguageComponent lc) { statements.Add(lc); } public override void Run(ProgramBookmarkManager mgr) { } } }
ProgramComponent.LanguageComponent.IfElseLanguageComponent類代碼:
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ namespace ProgramComponent.LanguageComponent { using System; using System.Linq; using System.Linq.Expressions; public class IfElseLanguageComponent : LanguageComponentBlock { public Func<bool> Exp { get; set; } public override void Run(ProgramBookmarkManager mgr) { if (Exp()) base.Statements[0].Run(mgr); else base.Statements[1].Run(mgr); } } }
檢查流程代碼,OrderCheckFlows\OrderSubmitFlows類代碼:
/*============================================================================== * Author:深度訓練 * Create time: 2013-08-10 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實踐; *==============================================================================*/ namespace ConsoleApplication1 { using System; using ProgramComponent; using ProgramComponent.LanguageComponent; [Serializable] public class OrderCheckFlows : LanguageComponent { private ProgramBookmarkManager BookmarkManager = new ProgramBookmarkManager(); public OrderCheckFlows(ProgramBookmarkManager bookmarkManager) { this.BookmarkManager = bookmarkManager; BookmarkManager.Add(new ProgramBookmark("checkPrices", new ProgramBookmarkLocation(CheckOrderPrices))); } public override void Run(ProgramBookmarkManager mgr) { this.BookmarkManager = mgr; StartCheck(); } public void StartCheck() { BookmarkManager.Resume("checkPrices", null); } #region business flows public void CheckOrderPrices(ProgramComponent.ProgramBookmark nextCheck) { Console.WriteLine("checkPrices..."); BookmarkManager.Remove(nextCheck); BookmarkManager.Add(new ProgramBookmark("checkItems", new ProgramBookmarkLocation(CheckOrderItems))); BookmarkManager.Resume("checkItems", true); } public void CheckOrderItems(ProgramComponent.ProgramBookmark nextCheck) { if ((bool)nextCheck.Payload) Console.WriteLine("checkItems..."); else Console.WriteLine("end check items."); BookmarkManager.Remove(nextCheck); } #endregion } [Serializable] public class OrderSubmitFlows : LanguageComponent { private ProgramBookmarkManager BookmarkManager = new ProgramBookmarkManager(); public OrderSubmitFlows(ProgramBookmarkManager bookmarkManager) { this.BookmarkManager = bookmarkManager; BookmarkManager.Add(new ProgramBookmark("CheckSubmitPrices", new ProgramBookmarkLocation(CheckSubmitPrices))); } public override void Run(ProgramBookmarkManager mgr) { this.BookmarkManager = mgr; StartCheck(); } public void StartCheck() { BookmarkManager.Resume("CheckSubmitPrices", null); } #region business flows public void CheckSubmitPrices(ProgramComponent.ProgramBookmark nextCheck) { Console.WriteLine("CheckSubmitPrices..."); BookmarkManager.Remove(nextCheck); BookmarkManager.Add(new ProgramBookmark("CheckSubmitItems", new ProgramBookmarkLocation(CheckSubmitItems))); BookmarkManager.Resume("CheckSubmitItems", true); } public void CheckSubmitItems(ProgramComponent.ProgramBookmark nextCheck) { if ((bool)nextCheck.Payload) Console.WriteLine("CheckSubmitItems..."); else Console.WriteLine("end check CheckSubmitItems."); BookmarkManager.Remove(nextCheck); } #endregion } }
調(diào)用代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { using ProgramComponent; using ProgramComponent.LanguageComponent; class Program { static void Main(string[] args) { ProgramBookmarkManager bookmarkManager = new ProgramBookmarkManager(); OrderCheckFlows orderCheckFlow = new OrderCheckFlows(bookmarkManager); OrderSubmitFlows submitCheckFlow = new OrderSubmitFlows(bookmarkManager); IfElseLanguageComponent languageComponent = new IfElseLanguageComponent(); languageComponent.Exp = () => { return true; }; languageComponent.AddLangugateComponent(orderCheckFlow); languageComponent.AddLangugateComponent(submitCheckFlow); languageComponent.Run(bookmarkManager); Console.ReadLine(); } } }
一切都已經(jīng)被對象化,我們來看一下邏輯;
圖5:
這里的返回值決定了后面要執(zhí)行的語句組件的路徑,如果是true,則應(yīng)該檢查OrderCheckFlows流程;
圖6:
如果是false,則應(yīng)該檢查OrderSubmitFlows流程;
圖7:
可恢復語句對象模型基本構(gòu)造完成,當然復雜的問題還需要仔細的去分析設(shè)計,這里只是一個簡單的示例;
跟代碼書簽管理器一個道理,這里我們也可以實現(xiàn)一個LanguageComponentManager來對LanguageComponent管理,當然也要看需要不需要;可恢復語句管理器其實有很多文章可以做,因為它是所有語句組件的中心,這對于后面的持久化有很大的用處;
//由于內(nèi)容比較多且相當抽象,下一篇文章介紹;
所有的語句代碼都已經(jīng)被對象化,但是在運行時需要一個中心來管理這些被對象化的語句組件,因為我們要脫離對棧的依賴;一組語句組件是單個示例流程的一部分,但是我們可能會存在很多一起并行運行的流程,所以這是必須要提供的運行時;
//由于內(nèi)容比較多且相當抽象,下一篇文章介紹;
領(lǐng)域驅(qū)動設(shè)計在使用規(guī)約模式的時候會存在動態(tài)配置的需求,可以參見這里的語句組件模型,讓規(guī)約最大化的提供配置;
//由于內(nèi)容比較多且相當抽象,下一篇文章介紹;
//由于內(nèi)容比較多且相當抽象,下一篇文章介紹;
//由于內(nèi)容比較多且相當抽象,下一篇文章介紹;
示例Demo地址:http://files.cnblogs.com/wangiqngpei557/ConsoleApplication3.zip
作者:王清培
出處:http://wangqingpei557.blog.51cto.com/
本文版權(quán)歸作者和51CTO共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權(quán)利。
網(wǎng)頁名稱:.NET框架設(shè)計(高級框架架構(gòu)模式)—鈍化程序、邏輯凍結(jié)、凍結(jié)程序的延續(xù)、瞬間轉(zhuǎn)移
本文URL:http://jinyejixie.com/article8/pochop.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、網(wǎng)站營銷、網(wǎng)站制作、做網(wǎng)站、靜態(tài)網(wǎng)站、網(wǎng)站設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)