日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

.Net行為型設(shè)計(jì)模式之命令模式(Command)_基礎(chǔ)應(yīng)用

作者:springsnow ? 更新時(shí)間: 2022-07-24 編程語言

一、動(dòng)機(jī)(Motivate)

在我們的現(xiàn)實(shí)生活中有很多例子可以拿來說明這個(gè)模式,我們還拿吃餃子這個(gè)事情來說。我的奶奶說了,今天想吃餃子,發(fā)出了命令,然后我奶奶就去看電視去了。我們夫妻倆收到命令就開始和面,做餃子餡,包餃子。餃子包好了,我們就休息一會(huì),等下午5點(diǎn)就開始燒水煮餃子了,晚飯的時(shí)間到了,我奶奶按時(shí)吃上了餃子。還有很多例子,就不一一列舉了。

在軟件構(gòu)建過程中,“行為請求者”與“行為實(shí)現(xiàn)者”通常呈現(xiàn)一種“緊耦合”。但在某些場合——比如需要對行為進(jìn)行“記錄、撤銷/重做(undo/redo)、事務(wù)”等處理,這種無法抵御變化的緊耦合是不合適的。在這種情況下,如何將“行為請求者”與“行為實(shí)現(xiàn)者”解耦?將一組行為抽象為對象,可以實(shí)現(xiàn)二者之間的松耦合。

二、意圖(Intent)

將一個(gè)請求封裝為一個(gè)對象,從而使你可用不同的請求對客戶(客戶程序,也是行為的請求者)進(jìn)行參數(shù)化;對請求排隊(duì)或記錄請求日志,以及支持可撤銷的操作。???????????????????????????????? ——《設(shè)計(jì)模式》GoF

三、結(jié)構(gòu)圖(Structure)

四、模式的組成

從命令模式的結(jié)構(gòu)圖可以看出,它涉及到五個(gè)角色,它們分別是:
(1)、客戶角色(Client):創(chuàng)建具體的命令對象,并且設(shè)置命令對象的接收者。注意這個(gè)不是我們常規(guī)意義上的客戶端,而是在組裝命令對象和接收者,或許,把這個(gè)Client稱為裝配者會(huì)更好理解,因?yàn)檎嬲褂妹畹目蛻舳耸菑腎nvoker來觸發(fā)執(zhí)行。
(2)、命令角色(Command):聲明了一個(gè)給所有具體命令類實(shí)現(xiàn)的抽象接口。
(3)、具體命令角色(ConcreteCommand):命令接口實(shí)現(xiàn)對象,是“虛”的實(shí)現(xiàn);通常會(huì)持有接收者,并調(diào)用接收者的功能來完成命令要執(zhí)行的操作。
(4)、請求者角色(Invoker):要求命令對象執(zhí)行請求,通常會(huì)持有命令對象,可以持有很多的命令對象。這個(gè)是客戶端真正觸發(fā)命令并要求命令執(zhí)行相應(yīng)操作的地方,也就是說相當(dāng)于使用命令對象的入口。
(5)、接受者角色(Receiver):接收者,真正執(zhí)行命令的對象。任何類都可能成為一個(gè)接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。

五、命令模式的代碼實(shí)現(xiàn)

下面以生活中吃餃子為例來說說如何實(shí)現(xiàn)命令模式吧。今天早上,我奶奶就發(fā)布了命令,說她老人家想吃豬肉大蔥餡的餃子。我奶奶腿腳不好,就讓我爸爸捎個(gè)話給我們夫妻倆,晚上要吃豬肉大蔥餡的餃子。我瞬間就明白了,這個(gè)偉大的任務(wù)就落到我們夫妻倆肩上了。說做就做,保證晚飯能吃上熱氣騰騰的餃子,具體實(shí)現(xiàn)代碼如下:

static void Main(string[] args)
{
    //奶奶想吃豬肉大蔥餡的餃子
    PatrickLiuAndWife liuAndLai = new PatrickLiuAndWife();//命令接受者
    Command command = new MakeDumplingsCommand(liuAndLai);//命令
    PaPaInvoker papa = new PaPaInvoker(command); //命令請求者

    //奶奶發(fā)布命令
    papa.ExecuteCommand();

    //奶奶說不想吃餃子了
    papa.Undo();
}

//這個(gè)類型就是請求者角色--也就是我爸爸的角色,告訴奶奶要吃餃子
public sealed class PaPaInvoker
{
    //我爸爸從奶奶那里接受到的命令
    private Command _command;

    //爸爸開始接受具體的命令
    public PaPaInvoker(Command command)
    {
        this._command = command;
    }

    //爸爸給我們下達(dá)命令
    public void ExecuteCommand()
    {
        _command.MakeDumplings();
    }

    public void Undo()
    {
        _command.UndoMakeDumplings();
    }
}

//該類型就是抽象命令角色--Commmand,定義了命令的抽象接口,任務(wù)是包餃子
public abstract class Command
{
    //真正任務(wù)的接受者
    protected PatrickLiuAndWife _worker;

    protected Command(PatrickLiuAndWife worker)
    {
        _worker = worker;
    }

    //該方法就是抽象命令對象Command的Execute方法
    public abstract void MakeDumplings();
    public abstract void UndoMakeDumplings();

}

//該類型是具體命令角色--ConcreteCommand,這個(gè)命令完成制作“豬肉大蔥餡”的餃子
public sealed class MakeDumplingsCommand : Command
{
    public MakeDumplingsCommand(PatrickLiuAndWife worker) : base(worker) { }

    //執(zhí)行命令--包餃子
    public override void MakeDumplings()
    {
        //執(zhí)行命令---包餃子
        _worker.Execute("今天包的是農(nóng)家豬肉和農(nóng)家大蔥餡的餃子");
    }
    public override void UndoMakeDumplings()
    {
        //執(zhí)行命令---撤銷包餃子
        _worker.Execute("撤銷包餃子");
    }
}

//該類型是具體命令接受角色Receiver,具體包餃子的行為是我們夫妻倆來完成的
public sealed class PatrickLiuAndWife
{
    //這個(gè)方法相當(dāng)于Receiver類型的Action方法
    public void Execute(string job)
    {
        Console.WriteLine(job);
    }
}

六、命令模式的實(shí)現(xiàn)要點(diǎn):

1、Command模式的根本目的在于將“行為請求者”與“行為實(shí)現(xiàn)者”解耦,在面向?qū)ο笳Z言中,常見的實(shí)現(xiàn)手段是“將行為抽象為對象”。
2、實(shí)現(xiàn)Command接口的具體命令對象ConcreteCommand有時(shí)候根據(jù)需要可能會(huì)保存一些額外的狀態(tài)信息。
3、通過使用Composite組合模式,可以將多個(gè)命令封裝為一個(gè)“復(fù)合命令”MacroCommand。
4、Command模式與C#中的Delegate有些類似。但兩者定義行為接口的規(guī)范有所區(qū)別:Command以面向?qū)ο笾械摹敖涌?實(shí)現(xiàn)”來定義行為接口規(guī)范,更嚴(yán)格,更符合抽象原則;Delegate以函數(shù)簽名來定義行為接口規(guī)范,更靈活,但抽象能力比較弱。
5、使用命令模式會(huì)導(dǎo)致某些系統(tǒng)有過多的具體命令類。某些系統(tǒng)可能需要幾十個(gè),幾百個(gè)甚至幾千個(gè)具體命令類,這會(huì)使命令模式在這樣的系統(tǒng)里變得不實(shí)際。

1、命令模式的優(yōu)點(diǎn):

(1)、命令模式使得新的命令很容易被加入到系統(tǒng)里。

(2)、可以設(shè)計(jì)一個(gè)命令隊(duì)列來實(shí)現(xiàn)對請求的Undo和Redo操作。
(3)、可以較容易地將命令寫入日志。
(4)、可以把命令對象聚合在一起,合成為合成命令。合成命令式合成模式的應(yīng)用。

2、命令模式的缺點(diǎn):

使用命令模式可能會(huì)導(dǎo)致系統(tǒng)有過多的具體命令類。這會(huì)使得命令模式在這樣的系統(tǒng)里變得不實(shí)際。

3、命令模式的使用場景:

(1)、系統(tǒng)需要支持命令的撤銷(undo)。命令對象可以把狀態(tài)存儲(chǔ)起來,等到客戶端需要撤銷命令所產(chǎn)生的效果時(shí),可以調(diào)用undo方法把命令所產(chǎn)生的效果撤銷掉。命令對象還可以提供redo方法,以供客戶端在需要時(shí),再重新實(shí)現(xiàn)命令效果。
(2)、系統(tǒng)需要在不同的時(shí)間指定請求、將請求排隊(duì)。一個(gè)命令對象和原先的請求發(fā)出者可以有不同的生命周期。意思為:原來請求的發(fā)出者可能已經(jīng)不存在了,而命令對象本身可能仍是活動(dòng)的。這時(shí)命令的接受者可以在本地,也可以在網(wǎng)絡(luò)的另一個(gè)地址。命令對象可以串行地傳送到接受者上去。
(3)、如果一個(gè)系統(tǒng)要將系統(tǒng)中所有的數(shù)據(jù)消息更新到日志里,以便在系統(tǒng)崩潰時(shí),可以根據(jù)日志里讀回所有數(shù)據(jù)的更新命令,重新調(diào)用方法來一條一條地執(zhí)行這些命令,從而恢復(fù)系統(tǒng)在崩潰前所做的數(shù)據(jù)更新。
(4)、系統(tǒng)需要使用命令模式作為“CallBack(回調(diào))”在面向?qū)ο笙到y(tǒng)中的替代。Callback即是先將一個(gè)方法注冊上,然后再以后調(diào)用該方法。

七、.NET 中命令模式的實(shí)現(xiàn)

由于.NET有了Delegate,它很少很少用到Command。它只要需要用到行為抽象,它都用Delegate去做。因?yàn)檫@是Framework,這是和業(yè)務(wù)領(lǐng)域相關(guān)度不大的基礎(chǔ)建設(shè)層面,它是不太需要用到OO的層面。對于我們來說,我們建議更多地用Command去實(shí)現(xiàn)。

原文鏈接:https://www.cnblogs.com/springsnow/p/11358455.html

欄目分類
最近更新