一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

把委托說透(1):開始委托之旅 委托與接口

委托,本是一個非常基礎的.NET概念,但前一陣子在園子里卻引起軒然大波。先是Michael Tao隨筆讓人們將委托的寫法與茴香豆聯系到了一起,接著老趙又用一系列文章分析委托寫法的演變,并告誡“嘲笑孔乙己的朋友們,你們在一味鄙視“茴”的四種寫法的同時,說不定也失去了一個了解中國傳統文化的機會呢!”。

在我個人看來,委托是.NET Framework中一個非常炫的特性,絕不會向有些評論里說的那樣,根本沒有機會接觸。恰恰相反,我們幾乎每天都會接觸委托,使用委托。

其實園子里已經有了很多關于委托的文章,比較有代表性的有:

1. C# 中的委托和事件及其

2. C#委托,事件理解入門 (譯稿)

3. 委托揭秘

4. ……

本系列試圖從個人對于委托的理解展開,對委托的內涵和外延均加以討論。文中有何不妥或不正確的地方,歡迎大家拍磚斧正。

好了,下面讓我從一個示例開始,一步一步引入委托的概念。

從示例開始

假設一個系統的用戶登錄模塊有如下所示的代碼

class User{    public string Name { get; set; }    public string Password { get; set; }}class UserService{    public void Register(User user)    {         if (user.Name == "Kirin")        {            Log("注冊失敗,已經包含名為" + user.Name + "的用戶");        }        else        {            Log("注冊成功!");        }    }    privte void Log(string message)    {        Console.WriteLine(message);    }}

UserService類封裝用戶登錄的邏輯,并根據不同的登錄情況向控制臺打印不同的日志內容。當程序關閉時,所記錄的日志自然也隨之消失。

客戶端的代碼為

class Program{    static void Main(string[] args)    {        User user = new User { Name = "Kirin", Password = "123" };        UserService service = new UserService();        service.Register(user);        Console.ReadLine();    }}

 

使用策略模式

然而這樣的設計肯定是無法滿足用戶的需求的,用戶肯定希望能夠查看以前的日志記錄,而不僅僅是程序打開以后的內容。如果我們僅僅修改Log方法的實現,那么用戶需求再次改變時我們該如何處理呢?難道要無休止地修改Log方法嗎?

既然日志記錄的方式是變化的根源,我們自然會想到將其進行封裝。我們創建一個名為ILog的接口。

interface ILog{    void Log(string message);}

并創建兩個實現了ILog的類,ConsoleLog和TextLog,分別用來向控制臺和文本文件輸出日志內容。

class ConsoleLog : ILog{    public void Log(string message)    {        Console.WriteLine(message);    }}

 

class TextLog : ILog{    public void Log(string message)    {        using (StreamWriter sw = File.AppendText("log.txt"))        {            sw.WriteLine(message);            sw.Flush();            sw.Close();        }    }}

在UserService類中添加一個ILog類型的屬性LogStrategy。

class UserService{    public ILog LogStrategy { get; set; }    public UserService()    {        LogStrategy = new ConsoleLog();    }    public void Register(User user)    {         if (user.Name == "Kirin")        {            LogStrategy.Log("注冊失敗,已經包含名為" + user.Name + "的用戶");        }        else        {            LogStrategy.Log("注冊成功!");        }    }}

客戶端代碼變為如下形式。

class Program{    static void Main(string[] args)    {        User user = new User { Name = "Kirin", Password = "123" };        UserService service = new UserService { LogStrategy = new TextLog() };        service.Register(user);        Console.ReadLine();    }}

在聲明UserService的時候,還可以將將LogStrategy設置為TextLog。這樣在UserService進行邏輯處理時,使用的LogStrategy即為TextLog,日志將輸出到文本文件中。

我們在干什么?我們在重構。重構的結果是什么?重構的結果是實現了一個簡單的策略模式。

使用委托

然而策略模式仍然不能滿足客戶的需求,這是為什么呢?

1. 用戶也許會希望自定義Log的實現。當然,你可以通過在客戶代碼處擴展ILog來實現自己的日志記錄方式。如

class TextBoxLog : ILog{    private TextBox textBox;    public TextBoxLog(TextBox textBox)    {        this.textBox = textBox;
this.textBox.Multiline = true; }
public void Log(string message) { textBox.AppendText(message); textBox.AppendText(Environment.NewLine); }}

但這種方案是否過于復雜呢?如果用戶希望在ListView或其他控件上顯示,是否需要逐個創建新類呢?并且這樣的實現是否與客戶端的耦合過于緊密呢?比如用戶希望在ListView的各個列中顯示日志內容、時間、來源等不同內容,那么在ListViewLog中對ListView硬編碼是否很難重用呢?

2. 用戶也許會希望同時使用多種日志記錄方式。比如,同時向控制臺、文本文件、客戶端控件和事件查看器中輸出日志。你當然可以在UserService中維護一個List,但這時UserService的職責過多,顯然違反了SRP。

下面介紹本文的主角:委托。

我們首先來創建一個名為Log的委托,它接收一個string類型的參數。

public delegate void Log(string message);

然后在UserService類中添加一個Log委托類型的屬性LogDelegate。

class UserService{    public Log LogDelegate { get; set; }


// …}

在客戶端,我們直接聲明兩個靜態方法,它們都包含一個string類型的參數,并且沒有返回值。

static void LogToConsole(string message){    Console.WriteLine(message);}static void LogToTextFile(string message){     using (StreamWriter sw = File.AppendText("log.txt"))    {        sw.WriteLine(message);        sw.Flush();        sw.Close();    }}

客戶端聲明UserService的代碼變為

static void Main(string[] args){    User user = new User { Name = "Kirin", Password = "123" };    UserService service = new UserService();    service.LogDelegate = LogToConsole;    service.LogDelegate += LogToTextFile;    service.Register(user);    Console.ReadLine();}

在構造委托時,我們還可以使用匿名方法和Lambda表達式,在老趙的文章中詳細闡述了這些寫法的演變。

對于何時使用委托,何時使用接口(即策略模式),MSDN中有明確的描述

在以下情況下,請使用委托:

    當使用事件設計模式時。

    當封裝靜態方法可取時。

    當調用方不需要訪問實現該方法的對象中的其他屬性、方法或接口時。

    需要方便的組合。

    當類可能需要該方法的多個實現時。

在以下情況下,請使用接口:

    當存在一組可能被調用的相關方法時。

    當類只需要方法的單個實現時。

    當使用接口的類想要將該接口強制轉換為其他接口或類類型時。

    當正在實現的方法鏈接到類的類型或標識時:例如比較方法。

您可能覺得上面的例子闡述委托和接口有些過于牽強,事實上有些時候的確很難選擇使用接口還是委托。Java中沒有委托,但所有委托適用的情況同樣可以使用包含單一方法的接口來實現的。在某種程度上,可以說委托是接口(僅定義了單一方法)的一種輕量級實現,它更靈活,也更方便。

到此為止,我們一步一步用委托重構了最初的代碼。再接下來的隨筆中,我們將開始更深一步的討論。

NET技術把委托說透(1):開始委托之旅 委托與接口,轉載需保留來源!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

主站蜘蛛池模板: 亚洲乱人伦精品图片 | 成人午夜视频网站 | 91精品欧美成人 | 精品精品国产高清a毛片牛牛 | 天天天天天干 | 久久婷婷五综合一区二区 | 欧美视频一 | 午夜在线免费视频 | 极品销魂一区二区三区 | 岛国大片在线 | 欧美特黄a级高清免费大片 欧美特黄a级高清免费看片 | 在线视频亚洲一区 | 深爱五月婷婷 | 任我鲁任我在线精品视频 | 欧美成人丝袜一区二区 | 午夜欧美福利视频 | 美女国内精品自产拍在线播放 | 亚洲精品成人久久久影院 | 伊人狼人久久 | 国产精品福利小视频 | 亚洲天堂一区二区在线观看 | 中日韩新区 | 酒色网址| www.色五月| 婷婷四房综合激情五月在线 | 黄色网 在线播放 | 国产精品亚洲欧美一级久久精品 | 久久九九视频 | 美女裸体自慰在线观看 | 久久精品国产精品青草不卡 | 火辣福利视频 | 欧美亚洲综合激情在线 | 欧美日韩一区二区亚洲 | 日韩视频免费一区二区三区 | 欧美中文字幕一二三四区 | 精品国产国产综合精品 | 高清一区高清二区视频 | 成人小视频在线免费观看 | 亚洲www| 免费色网 | 手机天堂 |