1. 程式人生 > >Telerik UI for ASP.NET AJAX教程:C#中的函式程式設計

Telerik UI for ASP.NET AJAX教程:C#中的函式程式設計

【下載Telerik UI for ASP.NET AJAX最新版本】

在面向物件程式設計(OOP)中,我們習慣於使用物件集合或簡單資料型別。我們經常使用LINQ對這些集合進行排序和過濾,作為業務邏輯行為或資料轉換的一部分。雖然這些是我們經常執行的有用任務,但很容易忘記C#中的函式可以被視為資料。如果我們重新考慮作為資料的函式思考,它使我們能夠發現OOP中標準問題的替代解決方案。

在本文中,我們將看一下C#Functional Programming研討會的一個例子。該場景概述了用於對撲克牌進行評分的解決方案。我們將研究一種利用函式作為資料的解決方案的替代模式。通過這種新模式,我們將為遊戲的評分機制提供靈活性。

(一)評分標準

首先,讓我們來看看用於產生最終得分的各個評分函式。每個功能都是一個規則,用於確定手牌是否符合標準。

private bool HasFlush(IEnumerable<Card> cards) => ...;
private bool HasRoyalFlush(IEnumerable<Card> cards) => ...;
private bool HasPair(IEnumerable<Card> cards) => ...;
private bool HasThreeOfAKind(IEnumerable<Card> cards) => ...;
private bool HasFourOfAKind(IEnumerable<Card> cards) => ...;
private bool HasFullHouse(IEnumerable<Card> cards) => ...;
private bool HasStraightFlush(IEnumerable<Card> cards) => ...;
private bool HasStraight(IEnumerable<Card> cards) => ...;

下圖說明了遊戲得分的規則。雖然這些函式表明手是否符合標準,但它們不會直接影響手的最終得分。我們需要安排規則並按重要性評估它們以產生分數並將其分配給HandRank的列舉型資料。

telerik

(二)確定分數

使用規則,我們可以通過幾種不同的方式確定最終得分值。以下每個示例在技術上都是正確的,並提供其自身的可讀性和簡單性。每種方法的消極方面是規則執行的順序是“hard coded”。

2.1維護狀態

這種評估分數的方法使用臨時佔位符值來跟蹤分數。每次評估都會進行,score並使用最好的HandRank進行更新。此方法非常明確,但涉及完成任務所不需要的額外程式碼和變數。

public HandRank GetScore(Hand hand)
{
    var score = HandRank.HighCard;
    if (HasPair(hand.Cards)) { score = HandRank.Pair; }
     ... 
    if (HasRoyalFlush(hand.Cards)) { score = HandRank.RoyalFlush; }
    return score;
}

2.2返回值

使用返回早期模式允許我們編寫直觀的程式碼,通過在發現評估為真時立即從函式返回來返回最佳HandRank。由於應用程式需要新規則,因此該方法易於閱讀且易於修改。

public HandRank GetScore(Hand hand)
{
    if (HasRoyalFlush()) return HandRank.RoyalFlush;
     ...
    if (HasPair()) return HandRank.Pair;
    return HandRank.HighCard;
}

2.3三元表示式

可以使用三元運算子將函式寫為單個表示式。這與返回早期方法具有類似的效果,但程式碼更少。對於某些人來說,這種方法的可讀性可能比其他人更容易。

在所有前面的例子中,操作順序是至關重要的。如果我們決定在此評分函式中新增新規則,那麼我們需要確保以正確的順序插入它們以確定正確的分數。

(二)思考功能

GetScore操作正逐步完成標準評估,並將結果為true的第一個規則與匹配的HandRank匹配。我們可以從函數語言程式設計思維方式中解決問題,而不是將函式作為單獨的語句進行評估。讓我們通過將函式視為資料來改變我們對問題的看法。

如果我們將各個評分函式看作資料,我們就可以識別出一種模式。考慮以下評分函式的signature。

private bool HasFlush(IEnumerable<Card> cards) => ...;
private bool HasRoyalFlush(IEnumerable<Card> cards) => ...;
private bool HasPair(IEnumerable<Card> cards) => ...;
private bool HasThreeOfAKind(IEnumerable<Card> cards) => ...;
private bool HasFourOfAKind(IEnumerable<Card> cards) => ...;
private bool HasFullHouse(IEnumerable<Card> cards) => ...;
private bool HasStraightFlush(IEnumerable<Card> cards) => ...;
private bool HasStraight(IEnumerable<Card> cards) => ...;

每個功能都屬於同一型別Func, bool>。由於我們有許多相同型別的資料,我們可以將它們安排在一個集合或陣列中。接下來,我們需要將每個函式與它所代表的HandRank相匹配。例如:HasPair將得分為HandRank.Pair。使用元組,我們可以輕鬆建立此對映,而無需專門的類。在C#7.1中,我們可以通過簡單地在括號中包含多個值來建立元組。使用函式及其對映的列舉器,我們可以構建集合。

private List<(Func<IEnumerable<Card>, bool> eval, HandRank rank)> GameRules() =>
   new List<(Func<IEnumerable<Card>, bool> eval, HandRank rank)>
   {
               (cards => HasRoyalFlush(cards), HandRank.RoyalFlush),
               (cards => HasStraightFlush(cards), HandRank.StraightFlush),
               (cards => HasFourOfAKind(cards), HandRank.FourOfAKind),
               (cards => HasFullHouse(cards), HandRank.FullHouse),
               (cards => HasFlush(cards), HandRank.Flush),
               (cards => HasStraight(cards), HandRank.Straight),
               (cards => HasThreeOfAKind(cards), HandRank.ThreeOfAKind),
               (cards => HasPair(cards), HandRank.Pair),
               (cards => true, HandRank.HighCard),
   };

為了保持程式碼整潔,我們將把集合的構造包裝在一個名為GameRules的函式中。我們以後可以將其作為其他遊戲規則的可擴充套件點。通過將排名系統移到GetScore方法之外,可以修改或替換新的評估和排名。對於可能的最低排名,我們將簡單地使用true來表示預設評估。

(三)使用LINQ進行重構

現在我們將使用LINQ重寫GetScore方法來評估列表。通過將列表中的專案視為資料,我們可以利用排序來確保它們以正確的順序執行。我們不再需要擔心“硬編碼”執行順序。我們可以使用.OrderByDescending(card => card.rank)將評估從最強等級排序到最弱,因為HandRank.RoyalFlush具有最高值。

public HandRank GetScore(Hand hand) => GameRules()
                    .OrderByDescending(rule => rule.rank)
                    .First(rule => rule.eval(hand.Cards)).rank;

最後,為了得到結果,我們將進行評估。最有效的方法是使用First LINQ方法。由於First是短路運算子,因此只要找到返回true的第一個專案,它就會停止對專案進行評估。當第一項計算結果為true時,我們將從資料集中獲取元組的排名值並返回它。排名值是我們的最終得分。

(四)結論

C#中的函式通常被認為是靜態語句,我們的應用程式可以使用它來更改系統中的資料狀態。通過將我們的觀點從命令性轉變為功能性,我們可以找到替代解決方案。為問題帶來功能性思維的一種方法是記住函式也是資料,並且符合許多與C#中其他資料型別相同的規則。在這個例子中,我們看到了一種功能方法如何將基於語句的硬編碼評估轉換為靈活的排序和基於地圖的評估。這個簡單的更改擴充套件了應用程式的功能,並在新增新條件時減少了摩擦,因為沒有預定義操作順序。

購買telerik正版授權的朋友可以點選"諮詢線上客服"哦~~~