真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

閱讀目錄:

朝陽網(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ī)則對象原型)

1】開篇介紹

通過上一篇的“.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í)吧;

2】元數(shù)據(jù)緩存池模式(在運(yùn)行時(shí)構(gòu)造元數(shù)據(jù)緩存池)

很多框架都有將特性放在屬性上面用來標(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ì)問題?

2.1】元數(shù)據(jù)設(shè)計(jì)模式(抽象出對數(shù)據(jù)的描述數(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:

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

這是我們的對象模型,那么我們?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:

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

到目前為止我們都是在為元數(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:

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

這個(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é)合具體的需求才行;

2.2】借助Dynamic來改變IOC、AOP動(dòng)態(tài)綁定的問題

要想在運(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:

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

畫紅線的部分是可以抽取來放入擴(kuò)展方法Add中的,在構(gòu)造的內(nèi)部是完全可以進(jìn)入到元數(shù)據(jù)緩存池中拿到這些數(shù)據(jù)然后直接動(dòng)態(tài)生成擴(kuò)展方法背后的真實(shí)方法;

2.3】元數(shù)據(jù)和模型綁定、元數(shù)據(jù)應(yīng)該隱藏在Model背后、元數(shù)據(jù)與DSL的關(guān)系

元數(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:

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

這可能是未來10年要改變的編程路線吧,我只是猜測;最后軟件將進(jìn)一步被自定義;

3】鏈?zhǔn)脚渲肈ynamic模式(愛不釋手的思維習(xí)慣編程)

再一次提起鏈?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:

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

紅線部分必須要轉(zhuǎn)換才能順利添加行為;

4】委托工廠模式(要優(yōu)于常見的 工廠,概念更加準(zhǔ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中使用的,都是在一些框架、工具中用來做靈活接口用的;

5】規(guī)則外掛(視委托為特殊的規(guī)則對象原型)

規(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 Func Specificaion { 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 Func Specificaion { 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:

.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧

注意這里的反序列化接口實(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)利。



網(wǎng)頁題目:.NET框架設(shè)計(jì)—常被忽視的框架設(shè)計(jì)技巧
文章網(wǎng)址:http://weahome.cn/article/ggdpej.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部