簡體   English   中英

將方法作為參數直接傳遞給調用方法

[英]Passing methods as parameter vs calling methods directly

我已經看到在一些例子中作為參數傳遞的方法。 如果我可以從另一個方法調用一個方法,為什么我應該將方法作為參數傳遞? 這個設計背后的目的是什么?

  1. 從另一個方法調用一個方法
  2. 使用delegate或Action將方法作為參數傳遞

傳遞方法作為參數可用於防止依賴性和耦合。 讓我們來看看它如何用於策略模式:

假設我們有一個方法PrintReport ,它打印一個給定的項目列表,可以根據參數按名稱或類型排序。 這是天真的方法:

public void PrintReport (List<Item> data, SortOrder sortBy)
{
    List<Item> sortedItems;
    switch (sortBy)
    {
        case SortOrder.Name: sortedItems = SortByName(data); break;
        case SortOrder.Type: sortedItems = SortByType(data); break;
    }

    Print(sortedItems);
}

它很簡單,但它的工作原理。 但是當我們想要添加新的排序順序時會發生什么? 我們需要更新SortOrder枚舉,進入PrintReport並添加一個新case並調用新的SortByWhatever方法。

但是如果我們將方法作為參數傳遞,我們的PrintReport可以更簡單,而不關心排序實現:

public void PrintReport (List<Item> data, Func<List<Item>, List<Item>> sorter)
{
    List<Item> sortedItems = sorter(data);
    Print(sortedItems);
}

現在無論如何都可以定義排序功能,甚至可能在PrintReport甚至不知道的不同組件中。 它可以是lambda函數或ad-hoc定義的匿名方法。 但在所有情況下,我們的方法將接收委托,使用它進行排序,然后打印報告。

這是一個用法示例。 起初看起來我們只是將開關/外殼移到了函數之外,這很重要,因為它允許不同的調用者具有不同的邏輯。 但要注意第三種情況。

public void HandleData()
{
    switch (ReportItemOrder)
    {
        case SortOrder.Name: PrintReport(data, SortByName); break;
        case SortOrder.Type: PrintReport(data, SortByType); break;
        case SortOrder.Whatever: 
        Func<List<Item>, List<Item>> customSort = (items) => /* do something */;
        PrintReport(data, customSort);
    }
}

委托通常用於將類和接口相互分離。

這是一個具體的例子。 假設您有一個負責繪制日歷的UI類,但您不希望它確切地知道如何將DateTime值格式化為字符串。

您可以將類定義為:

public sealed class MyCalendarDrawer
{
    private readonly Func<DateTime, string> _dateFormatter;

    public MyCalendarDrawer(Func<DateTime, string> dateFormatter)
    {
        _dateFormatter = dateFormatter;
    }

    public void Draw()
    {
        // Do some work that involves displaying dates...

        DateTime date = DateTime.Now;

        string dateString = _dateFormatter(date);

        // Display dateString somehow.
    }
}

這樣, MyCalendarDrawer不需要知道如何格式化日期 - 它被告知如何通過傳遞它可以調用的委托Func<DateTime, string>來完成它。

將功能視為一流類型具有其優點。 它為您提供功能編程的可能性。

以“事件處理”的經典案例為例,您肯定會將一個函數指針發送到另一個函數,作為事件發生時的回調。

同樣,這是另一個假設的例子

private void CallMeBack(out int type, Func<int> action)
{
   type = action();
}

現在我可以為此提供任何功能,如CallMeBack(a, ()=>return 1); CallMeBack(a, ()=>return 2);

你應該閱讀有關代表的信息。 例如,委托對於在給定方法完成時定義動態回調很有用。

偽代碼示例:

doSomething(); //your code
updateInterface(continueDoingSomething); //a generic method, passing a delegate

...

doAnythingElse();
updateInterface(continueDoingAnythingElse);

在此示例中,您可以定義一個泛型方法“updateInterface”,它作為回調調用作為委托傳入的動態方法。

如果不使用委托,則必須實現兩種(或更多種)不同的方法:

void updateInterfaceAndContinueDoingSomething(){}
void updateInterfaceAndContinueDoingAnythingElse(){}

事實上,函數傳遞給其他函數的每個例子都可以用實現傳遞給函數的給定接口的對象來表示。

換句話說,沒有明顯的理由代表比接口更好。 Java中即將推出的lambdas就是一個例子,而不是你真的需要能夠將一個函數傳遞給另一個函數才能擁有簡潔的語法。

換句話說,將函數傳遞給另一個函數的能力只是程序員工具箱中的一個工具,就像傳遞對象函數一樣。 雖然這可以說是更好的,但是人們可以擁有一種語言,它不支持將函數傳遞給函數 - Java - 並且仍然能夠具有相同的表達能力。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM