閱讀目錄:
朝陽網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),朝陽網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為朝陽近1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個(gè)售后服務(wù)好的朝陽做網(wǎng)站的公司定做!
1.開篇介紹
2.元數(shù)據(jù)緩存池模式(在運(yùn)行時(shí)構(gòu)造元數(shù)據(jù)緩存池)
2.1.元數(shù)據(jù)設(shè)計(jì)模式(抽象出對數(shù)據(jù)的描述數(shù)據(jù))
2.2.借助Dynamic來改變IOC、AOP動(dòng)態(tài)綁定的問題
2.3.元數(shù)據(jù)和模型綁定、元數(shù)據(jù)應(yīng)該隱藏在Model背后、元數(shù)據(jù)與DSL的關(guān)系
3.鏈?zhǔn)脚渲肈ynamic模式(愛不釋手的思維習(xí)慣編程)
4.委托工廠模式(要優(yōu)于常見的 工廠,概念更加準(zhǔn)確,減少污染)
5.規(guī)則外掛(視委托為特殊的規(guī)則對象原型)
通過上一篇的“.NET框架設(shè)計(jì)—常被忽視的C#設(shè)計(jì)技巧”一文來看,對于框架設(shè)計(jì)的技巧還是有很多人比較有興趣的,那么框架設(shè)計(jì)思想對于我們?nèi)粘i_發(fā)來說其實(shí)并不是很重要,但是對于我們理解框架背后的運(yùn)行原理至關(guān)重要;當(dāng)我們使用著LINQ靈活的語法的同時(shí)我們是否能理解它的背后運(yùn)行原理、設(shè)計(jì)原理更深一點(diǎn)就是它的設(shè)計(jì)模式及復(fù)雜的對象模型;
從一開始學(xué)習(xí).NET我就比較喜歡框架背后的設(shè)計(jì)模型,框架提供給我們的使用接口是及其簡單的,單純從使用上來看我們不會隨著對框架的使用時(shí)間而增加我們對框架內(nèi)部設(shè)計(jì)的理解,反而會養(yǎng)成一樣哪來即用的習(xí)慣,我們只有去了解、深挖它的內(nèi)部設(shè)計(jì)原理才是我們長久學(xué)習(xí)的目標(biāo);因?yàn)榭蚣艿膬?nèi)部設(shè)計(jì)模式是可以提煉出來并被總結(jié)的;
這篇文章總結(jié)了幾個(gè)我最近接觸的框架設(shè)計(jì)思想,可以稱他們?yōu)槟J剑挥捎跁r(shí)間關(guān)系,這里只是介紹加一個(gè)簡單的介紹和示例讓我們能基本的了解它并且能在日后設(shè)計(jì)框架的時(shí)候想起來有這么一個(gè)模式、設(shè)計(jì)方式可以借鑒;當(dāng)然,這每一節(jié)都是一個(gè)很大主題,用的時(shí)候在去細(xì)心的分析學(xué)習(xí)吧;
很多框架都有將特性放在屬性上面用來標(biāo)識某種東西,但是這種方式使用不當(dāng)?shù)脑挄π阅茉斐捎绊?;再從框架設(shè)計(jì)原則來講也是對DomainModel極大的污染,從EntityFramework5.0之前的版本我們就能體會到了,它原本是將部分Attribute加在了Entity上的,但是這畢竟是業(yè)務(wù)代碼的核心,原則上來說這不能有任何的污染,要絕對的POJO;后來5.0之后就完全獨(dú)立了DomainModel.Entity,所有的管理都在運(yùn)行時(shí)構(gòu)造綁定關(guān)系,因?yàn)樗蠩DMX元數(shù)據(jù)描述文件;
那么這些Attribute其實(shí)本質(zhì)是.NET在運(yùn)行時(shí)的一種元數(shù)據(jù),主要的目的是我們想在運(yùn)行時(shí)將它讀取出來,用來對某些方面的判斷;那么現(xiàn)在的問題是如果我們每次都去讀取這個(gè)Attribute是必須要走反射機(jī)制,當(dāng)然你可以找一些框架來解決這個(gè)問題;(我們這里討論的是你作為開發(fā)框架的設(shè)計(jì)者?。?/p>
反射影響性能這不用多講了,那么常規(guī)的做法是會在第一次反射之后將這些對象緩存起來,下次再用的時(shí)候直接在緩存中讀取;這沒有問題,這是解決了反射的性能問題,那么你的Attribute是否還要加在DomainModel中呢,如果加的話隨著代碼量的增加,這些都會成為后面維護(hù)的成本開銷;那么我們?nèi)绾螌⒏蓛舻腜OJO對象提供給程序員用,但是在后臺我們也能對POJO進(jìn)行強(qiáng)大的控制?這是否是一種設(shè)計(jì)問題?
我一直比較關(guān)注對象與數(shù)據(jù)之間的關(guān)系,面向?qū)ο蟮倪@種縱橫向關(guān)系如何平滑的與E-R實(shí)體關(guān)系模型對接,這一直是復(fù)雜軟件開發(fā)的核心問題;這里就用它來作為本章的示例的基本概要;
我們有一個(gè)基本的DomainModel聚合,如何在不影響本身簡潔性的情況下與E-R關(guān)系對接,比如我們在對聚合進(jìn)行一個(gè)Add操作如何被映射成對數(shù)據(jù)庫的Insert操作;我們來看一下元數(shù)據(jù)設(shè)計(jì)模式思想;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ConsoleApplication1.DomainModel { ////// Employee. public class Employee { ////// /// Primary id. /// public string EId { get; set; } ////// Name. /// public string Name { get; set; } ////// Sex. public SexType Sex { get; set; } ////// /// Address. /// public Address Address { get; set; } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ConsoleApplication1.DomainModel{////// Employee. publicclass Employee {////// /// Primary id./// publicstring EId { get; set; }////// Name./// publicstring Name { get; set; }////// Sex. public SexType Sex { get; set; }////// /// Address./// public Address Address { get; set; } }}
這里有一個(gè)以Employee實(shí)體為聚合根的聚合,里面包含一些基本的屬性,特別需要強(qiáng)調(diào)的是Sex屬性和Address,這兩個(gè)屬性分別是Complex類型的屬性; Complex類型的屬性是符合面向?qū)ο蟮男枰?,但是在關(guān)系型數(shù)據(jù)庫中是很難實(shí)現(xiàn)的,這里就需要我們用元數(shù)據(jù)將它描述出來并能在一些行為上進(jìn)行控制;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ConsoleApplication1.DomainModel { ////// Address . /// public struct Address { ////// Address name. /// public string AddressName { get; set; } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ConsoleApplication1.DomainModel{////// Address ./// publicstruct Address {////// Address name./// publicstring AddressName { get; set; } }}
這是Address類型的定義;
namespace ConsoleApplication1.DomainModel { ////// Sex type. /// public enum SexType { Male, Female } }
namespace ConsoleApplication1.DomainModel{////// Sex type./// publicenum SexType { Male, Female }}
這是SexType類型的定義;都比較簡單;
只有這樣我們才能對DomainModel進(jìn)行大面積的復(fù)雜設(shè)計(jì),如果我們不能將數(shù)據(jù)對象化我們無法使用設(shè)計(jì)模式,也就談不上擴(kuò)展性;
圖1:
這是我們的對象模型,那么我們?nèi)绾螌⑺c數(shù)據(jù)庫相關(guān)的信息提取出來形成獨(dú)立的元數(shù)據(jù)信息,對元數(shù)據(jù)的抽取需要?jiǎng)?、靜結(jié)合才行;
什么動(dòng)、靜結(jié)合,我們是否都會碰見過這樣的問題,很多時(shí)候我們的代碼在編譯時(shí)是確定的,但是有部分的代碼需要在運(yùn)行時(shí)動(dòng)態(tài)的構(gòu)造,甚至有些時(shí)候代碼需要根據(jù)當(dāng)前的IDE來生成才行,但是最終在使用的時(shí)候這些在不同階段生成的代碼都需要結(jié)合起來變成一個(gè)完整的元數(shù)據(jù)對象;
框架在很多時(shí)候需要跟IDE結(jié)合才能使使用變的順手,比如我們在開發(fā)自己的ORM框架如果不能直接嵌入到VisualStudio中的話,用起來會很不爽;當(dāng)我們用自己的插件去連接數(shù)據(jù)庫并且生成代碼的時(shí)候,有部分的元數(shù)據(jù)模型已經(jīng)在代碼中實(shí)現(xiàn),但是有部分需要我們動(dòng)態(tài)的去設(shè)置才行;
我們來看一下關(guān)于元數(shù)據(jù)的基礎(chǔ)代碼;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ORM.Meta { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; ////// Data source context. /// public abstract class DataBaseContext : List, IDisposable { /// /// Data base name. /// protected string DataBaseName { get; set; } ////// Connection string. /// protected string ConnectionString { get; set; } ////// Provider child class add table. /// /// protected virtual void AddTable(MetaTable table) { this.Add(table); } ////// Init context. /// protected virtual void InitContext() { } public void Dispose() { } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ORM.Meta{using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;////// Data source context./// publicabstractclass DataBaseContext : List, IDisposable {/// /// Data base name./// protectedstring DataBaseName { get; set; }////// Connection string./// protectedstring ConnectionString { get; set; }////// Provider child class add table./// /// protectedvirtualvoid AddTable(MetaTable table) {this.Add(table); }////// Init context./// protectedvirtualvoid InitContext() { }publicvoid Dispose() { } }}
這表示數(shù)據(jù)源上下文,屬于運(yùn)行時(shí)元數(shù)據(jù)的基礎(chǔ)設(shè)施;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ORM.Meta { using System.Collections.Generic; using System.Linq; ////// Database Table meta. /// public class MetaTable : List{ /// /// Table name. /// public string Name { get; set; } ////// Entity name. /// public string EntityName { get; set; } ////// Get column by column name. /// /// Column name. ///public MetaColumn GetColumnByName(string name) { var column = from item in this.ToList() where item.CoumnName == name select item; return column.FirstOrDefault(); } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ORM.Meta{using System.Collections.Generic;using System.Linq;////// Database Table meta./// publicclass MetaTable : List{/// /// Table name./// publicstring Name { get; set; }////// Entity name./// publicstring EntityName { get; set; }////// Get column by column name./// /// Column name.///public MetaColumn GetColumnByName(string name) { var column = from item inthis.ToList() where item.CoumnName == name select item;return column.FirstOrDefault(); } }}
簡單的表示一個(gè)Table,里面包含一系列的Columns;要記住在設(shè)計(jì)元數(shù)據(jù)基礎(chǔ)代碼的時(shí)候?qū)⒔涌诹舫鰜?,方便在IDE中植入初始化元數(shù)據(jù)代碼;
圖2:
到目前為止我們都是在為元數(shù)據(jù)做基礎(chǔ)工作,我們看一下有系統(tǒng)生成的聲明的元數(shù)據(jù)代碼;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ConsoleApplication1.Repository { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; ////// IDE Builder. /// public class DesignBuilder_DataBaseContext : ORM.Meta.DataBaseContext { //this begin IDE builder. protected override void InitContext() { ORM.Meta.MetaTable metaTable = new ORM.Meta.MetaTable() { Name = "TB_Employee", EntityName = "Employee" }; metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "EId", DataType = ORM.Meta.DataType.NVarchar }); metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "Name", DataType = ORM.Meta.DataType.NVarchar }); metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "Sex", DataType = ORM.Meta.DataType.Int }); metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "Address", DataType = ORM.Meta.DataType.NVarchar }); this.AddTable(metaTable); } //end } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ConsoleApplication1.Repository{using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;////// IDE Builder./// publicclass DesignBuilder_DataBaseContext : ORM.Meta.DataBaseContext {//this begin IDE builder.protectedoverridevoid InitContext() { ORM.Meta.MetaTable metaTable = new ORM.Meta.MetaTable() { Name = "TB_Employee", EntityName = "Employee" }; metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "EId", DataType = ORM.Meta.DataType.NVarchar }); metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "Name", DataType = ORM.Meta.DataType.NVarchar }); metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "Sex", DataType = ORM.Meta.DataType.Int }); metaTable.Add(new ORM.Meta.MetaColumn() { CoumnName = "Address", DataType = ORM.Meta.DataType.NVarchar });this.AddTable(metaTable); }//end}}
我假設(shè)這是我們框架在IDE中生成的部分元數(shù)據(jù)代碼,當(dāng)然你可以用任何方式來存放這些元數(shù)據(jù),但是最后還是要去對象化;
圖3:
這個(gè)目錄你可以直接隱藏,在后臺屬于你的框架需要的一部分,沒有必要讓它污染項(xiàng)目結(jié)構(gòu),當(dāng)然放出來也有理由;如果想讓你的LINQ或者表達(dá)式能直接穿過你的元數(shù)據(jù)上下文你需要直接擴(kuò)展;
static void Main(string[] args) { using (Repository.DesignBuilder_DataBaseContext context = new Repository.DesignBuilder_DataBaseContext()) { var employee = from emp in context.Employee where emp.EId == "Wqp123" select emp; } }
staticvoid Main(string[] args) {using (Repository.DesignBuilder_DataBaseContext context = new Repository.DesignBuilder_DataBaseContext()) { var employee = from emp in context.Employee where emp.EId == "Wqp123" select emp; } }
這里所有的代碼看上去很簡單,沒有多高深的技術(shù),這也不是本篇文章的目的,任何代碼都需要設(shè)計(jì)的驅(qū)動(dòng)才能產(chǎn)生價(jià)值,我們構(gòu)建的基礎(chǔ)代碼都是元數(shù)據(jù)驅(qū)動(dòng);當(dāng)你在運(yùn)行時(shí)把這些元數(shù)據(jù)放入Cache,既不需要加Attribute也不需要反射反而活動(dòng)了更大程度上的控制,但是要想構(gòu)建一個(gè)能用的元數(shù)據(jù)結(jié)構(gòu)需要結(jié)合具體的需求才行;
要想在運(yùn)行時(shí)完全動(dòng)態(tài)的綁定在編譯時(shí)定義的對象行為是需要強(qiáng)大的IOC框架支撐的,這樣的框架我們是做不來的或者需要很多精力,得不償失;對于元數(shù)據(jù)設(shè)計(jì)需要將AOP通過IOC的方式注入,在使用的時(shí)候需要改變一下思路,AOP的所有的切面在編譯時(shí)無法確定,后期通過IOC的方式將所有的行為注入;這里我們需要使用動(dòng)態(tài)類型特性;
使用Dynamic之后我們很多以往不能解決問題都可以解決,更向元編程跨進(jìn)了一步;對于IOC、AOP的使用也將變的很簡單,也有可能顛覆以往IOC、AOP的使用方式;而且動(dòng)態(tài)編程將在很大程度上越過設(shè)計(jì)模式了,也就是設(shè)計(jì)模式的使用方式在動(dòng)態(tài)編程中將不復(fù)存在了;
using (Repository.DesignBuilder_DataBaseContext context = new Repository.DesignBuilder_DataBaseContext()) { var employees = from emp in context.Employee where emp.EId == "Wqp123" select emp; Employee employee = new Employee() { EId = "Wqp123" }; var entityOpeartion = DynamicBehavior.EntityDymanicBehavior.GetEntityBehavior(employee); entityOpeartion.Add(); }
using (Repository.DesignBuilder_DataBaseContext context = new Repository.DesignBuilder_DataBaseContext()) { var employees = from emp in context.Employee where emp.EId == "Wqp123" select emp; Employee employee = new Employee() { EId = "Wqp123" }; var entityOpeartion = DynamicBehavior.EntityDymanicBehavior.GetEntityBehavior(employee); entityOpeartion.Add(); }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ConsoleApplication1.DynamicBehavior { using System; using System.Dynamic; public class EntityDymanicBehavior { public static dynamic GetEntityBehavior(TEntity entity) { //auto mark entity behavior dynamic dy = new ExpandoObject(); //load meta data mark dynamic behavior dy.Entity = entity; dy.Add = new Action(() => { Console.WriteLine("Action Add " + entity.GetType()); }); return dy; } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ConsoleApplication1.DynamicBehavior{using System;using System.Dynamic;publicclass EntityDymanicBehavior {publicstatic dynamic GetEntityBehavior(TEntity entity) {//auto mark entity behaviordynamic dy = new ExpandoObject();//load meta data mark dynamic behaviordy.Entity = entity; dy.Add = new Action(() => { Console.WriteLine("Action Add" + entity.GetType()); });return dy; } }}
圖4:
畫紅線的部分是可以抽取來放入擴(kuò)展方法Add中的,在構(gòu)造的內(nèi)部是完全可以進(jìn)入到元數(shù)據(jù)緩存池中拿到這些數(shù)據(jù)然后直接動(dòng)態(tài)生成擴(kuò)展方法背后的真實(shí)方法;
元數(shù)據(jù)的綁定應(yīng)該在運(yùn)行時(shí)動(dòng)態(tài)去完成,這點(diǎn)在以往我們需要大費(fèi)力氣,通過CodeDom、Emit才能完成,但是現(xiàn)在可以通過Dynamic、DLR來完成;思維需要轉(zhuǎn)變一下,動(dòng)態(tài)編程我們以往用的最多的地方在JS上,現(xiàn)在可以在C#中使用,當(dāng)然你也可以使用專門的動(dòng)態(tài)語言來寫更強(qiáng)大的元數(shù)據(jù)框架,IronRuby、IronPython都是很不錯(cuò)的,簡單的了解過Ruby的元數(shù)據(jù)編程,很強(qiáng)大,如果我們.NET程序員眼饞就用Iron…系列;
在開發(fā)復(fù)雜的動(dòng)態(tài)行為時(shí)盡量使用元數(shù)據(jù)設(shè)計(jì)思想,不要把數(shù)據(jù)和表示數(shù)據(jù)的數(shù)據(jù)揉在一起,要把他們分開,在運(yùn)行時(shí)Dynamic綁定;元數(shù)據(jù)應(yīng)該在Model的背后應(yīng)該在DomainModel的背后;
元數(shù)據(jù)和DSL有著天然的淵源,如果我們能把所有的語句組件化就可以將其封入.NET組件中,在IDE中進(jìn)行所見即所得的DSL設(shè)計(jì),然后生成可以直接運(yùn)行的Dynamic代碼,這可能也是元編程的思想之一吧;
圖5:
這可能是未來10年要改變的編程路線吧,我只是猜測;最后軟件將進(jìn)一步被自定義;
再一次提起鏈?zhǔn)骄幊淌怯X得它的靈活性無話可說,語言特性本身用在哪里完全需求驅(qū)動(dòng);把鏈?zhǔn)接脕碜雠渲孟嚓P(guān)的工作非常的合適;我們上面做了元數(shù)據(jù)配置相關(guān)的工作,這里我們試著用鏈?zhǔn)降姆椒▉砀纳扑?/p>
Dynamic類型本身的所有行為屬性都是可以動(dòng)態(tài)構(gòu)建的,那么我們把它放入鏈?zhǔn)降姆椒ㄖ腥?,根?jù)不同的參數(shù)來實(shí)現(xiàn)動(dòng)態(tài)的添加行為;
擴(kuò)展Dynamic類型需要使用ExpandoObject開始;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ConsoleApplication1.DynamicBehavior { using System; using System.Dynamic; public static class EntityDynamicBehaviorExtent { ////// Add dynamic method. /// /// ///public static ExpandoObject AddExten(this ExpandoObject entity) { dynamic dy = entity as dynamic; dy.Add = new Func (() => { Console.WriteLine("add " + entity); return entity; }); return entity; } /// /// where dynamic method. /// ////// /// /// public static ExpandoObject WhereExten (this ExpandoObject entity, Func where) { dynamic dy = entity as dynamic; dy.Where = where; return entity; } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ConsoleApplication1.DynamicBehavior{using System;using System.Dynamic;publicstaticclass EntityDynamicBehaviorExtent {////// Add dynamic method./// /// ///publicstatic ExpandoObject AddExten(this ExpandoObject entity) { dynamic dy = entity as dynamic; dy.Add = new Func (() => { Console.WriteLine("add" + entity); return entity; });return entity; }/// /// where dynamic method./// ////// /// /// publicstatic ExpandoObject WhereExten (this ExpandoObject entity, Func where) { dynamic dy = entity as dynamic; dy.Where = where;return entity; } }}
擴(kuò)展方法需要擴(kuò)展 ExpandoObject對象,DLR在運(yùn)行時(shí)使用的是ExpandoObject對象實(shí)例,所以我們不能夠直接擴(kuò)展Dynamic關(guān)鍵字;
Employee employee1 = new Employee() { EId = "Wqp123" }; var dynamicEntity = DynamicBehavior.EntityDymanicBehavior.GetEntityBehavior(employee1); (dynamicEntity as System.Dynamic.ExpandoObject).AddExten().WhereExten (emp => { Console.WriteLine("Where Method."); return emp.EId == "Wqp123"; }); dynamicEntity.Add().Where(employee1);
Employee employee1 = new Employee() { EId = "Wqp123" }; var dynamicEntity = DynamicBehavior.EntityDymanicBehavior.GetEntityBehavior(employee1); (dynamicEntity as System.Dynamic.ExpandoObject).AddExten().WhereExten (emp => { Console.WriteLine("Where Method.");return emp.EId == "Wqp123"; }); dynamicEntity.Add().Where(employee1);
圖6:
紅線部分必須要轉(zhuǎn)換才能順利添加行為;
對于工廠模式我們都會熟悉的一塌糊涂,各種各樣的工廠模式我們見的多了,但是這種類型的工廠使用方式你還真的沒見過;其實(shí)這種委托是想部分的邏輯交給外部來處理;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ConsoleApplication1.DomainModel { ////// Address factory. /// ///public delegate Address Factory(); /// /// Employee. public class Employee { public Employee() { } ////// /// Mark employee instance. /// /// /// /// /// address factory. public Employee(string eID, string name, SexType sex, Factory addressFactory) { this.EId = eID; this.Name = name; this.Sex = sex; this.Address = addressFactory(); } ////// Primary id. /// public string EId { get; set; } ////// Name. /// public string Name { get; set; } ////// Sex. public SexType Sex { get; set; } ////// /// Address. /// public Address Address { get; set; } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ConsoleApplication1.DomainModel{////// Address factory./// ///publicdelegate Address Factory();/// /// Employee. publicclass Employee {public Employee() { }////// /// Mark employee instance./// /// /// /// /// address factory.public Employee(string eID, string name, SexType sex, Factory addressFactory) {this.EId = eID;this.Name = name;this.Sex = sex;this.Address = addressFactory(); }////// Primary id./// publicstring EId { get; set; }////// Name./// publicstring Name { get; set; }////// Sex. public SexType Sex { get; set; }////// /// Address./// public Address Address { get; set; } }}
我們定義了一個(gè)用來創(chuàng)建Employee.Address對象的Factory,然后通過構(gòu)造函數(shù)傳入;
Employee employee2 = new Employee("Wqp123", "Wqp", SexType.Male, new Factory(() => { return new Address() { AddressName = "Shanghai" }; }));
Employee employee2 = new Employee("Wqp123", "Wqp", SexType.Male, new Factory(() => {returnnew Address() { AddressName = "Shanghai" }; }));
這里純粹為了演示方便,這種功能是不應(yīng)該在DommianModel中使用的,都是在一些框架、工具中用來做靈活接口用的;
規(guī)則外掛其實(shí)跟上面的委托工廠有點(diǎn)像,但是絕對不一樣的設(shè)計(jì)思想;如何將規(guī)則外掛出去,放入Cache中讓運(yùn)行時(shí)可以配置這個(gè)規(guī)則參數(shù);委托是規(guī)則的天然宿主,我們只要將委托序列化進(jìn)Cache就可以對它進(jìn)行參數(shù)的配置;
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/ namespace ConsoleApplication1.DomainModel.Specification { using System; using System.Linq.Expressions; ////// Employee add specification. /// [Serializable] public class EmployeeSpecificationAdd : System.Runtime.Serialization.IDeserializationCallback { ////// specification. /// [NonSerialized] private Func_specification; /// /// Gets specification. /// public FuncSpecificaion { get { return _specification; } } /// /// employee. /// private Employee Employee { get; set; } ////// Mark employee specificatoin. /// /// public EmployeeSpecificationAdd(Employee employee) { this.Employee = employee; InitSpecification(); } ////// Is Check. /// ///public bool IsCheck() { return _specification(Employee); } public void OnDeserialization(object sender) { InitSpecification(); } private void InitSpecification() { this._specification = (emp) => { return !string.IsNullOrWhiteSpace(emp.EId) && !string.IsNullOrWhiteSpace(emp.Name); }; } } }
/*============================================================================== * Author:深度訓(xùn)練 * Create time: 2013-08-04 * Blog Address:http://www.cnblogs.com/wangiqngpei557/ * Author Description:特定領(lǐng)域軟件工程實(shí)踐; *==============================================================================*/namespace ConsoleApplication1.DomainModel.Specification{using System;using System.Linq.Expressions;////// Employee add specification./// [Serializable]publicclass EmployeeSpecificationAdd : System.Runtime.Serialization.IDeserializationCallback {////// specification./// [NonSerialized]private Func_specification;/// /// Gets specification./// public FuncSpecificaion { get { return _specification; } }/// /// employee./// private Employee Employee { get; set; }////// Mark employee specificatoin./// /// public EmployeeSpecificationAdd(Employee employee) {this.Employee = employee; InitSpecification(); }////// Is Check./// ///publicbool IsCheck() {return _specification(Employee); }publicvoid OnDeserialization(object sender) { InitSpecification(); }privatevoid InitSpecification() {this._specification = (emp) => {return !string.IsNullOrWhiteSpace(emp.EId) && !string.IsNullOrWhiteSpace(emp.Name); }; } }}
圖7:
注意這里的反序列化接口實(shí)現(xiàn),因?yàn)長ambda無法進(jìn)行序列化,也沒有必要進(jìn)行序列化;
EmployeeSpecificationAdd specification = new EmployeeSpecificationAdd(employee2); Stream stream = File.Open("specification.xml", FileMode.Create); BinaryFormatter formattter = new BinaryFormatter(); formattter.Serialize(stream, specification); stream.Seek(0, SeekOrigin.Begin); specification = formattter.Deserialize(stream) as EmployeeSpecificationAdd; stream.Close(); stream.Dispose(); if (specification.IsCheck()) { Console.WriteLine("Ok..."); }
EmployeeSpecificationAdd specification = new EmployeeSpecificationAdd(employee2); Stream stream = File.Open("specification.xml", FileMode.Create); BinaryFormatter formattter = new BinaryFormatter(); formattter.Serialize(stream, specification); stream.Seek(0, SeekOrigin.Begin); specification = formattter.Deserialize(stream) as EmployeeSpecificationAdd; stream.Close(); stream.Dispose();if (specification.IsCheck()) { Console.WriteLine("Ok..."); }
既然能將規(guī)則序列化了,就可以把它放在任何可以使用的地方了,配置化已經(jīng)沒有問題了;
示例Demo地址:http://files.cnblogs.com/wangiqngpei557/ConsoleApplication2.zip
作者:王清培
出處:http://wangqingpei557.blog.51cto.com/
本文版權(quán)歸作者和51CTO共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。