2010-06-29 34 views
6

我必須採取一塊數據,並將大量可能的變量應用到它。我真的不喜歡使用大量if語句的想法,所以我正在尋求一種簡化方法的幫助,並使其更易於維護。編程高度複雜的商業/數學規則的最佳方法

作爲一個例子:

if (isSoccer) 
    val = soccerBaseVal; 
else if (isFootball) 
    val = footballBaseVal; 
.... // 20 different sports 

if (isMale) 
    val += 1; 
else 
    val += 5; 

switch(dayOfWeek) 
{ 
    case DayOfWeek.Monday: 
     val += 12; 
    ... 
} 

等。等。等。與可能在100-200不同的測試和式變化的範圍內。

這看起來像是一個維修噩夢。有什麼建議麼?

編輯:

爲了進一步增加的問題,許多變量只在某些情況下使用,所以它不僅僅是一組固定邏輯的不同值的更多。邏輯本身必須根據條件進行更改,可能會從以前的變量中應用條件(例如val> threshold)。

所以是的,我同意使用查找許多值,但我也必須有變量邏輯。

+0

可能的重複:http://stackoverflow.com/questions/1607252/how-to-simplify-complicated-business-if-logic – 2010-06-29 18:30:50

回答

7

避免大型交換結構的常用方法是將信息放入數據結構中。創建包含關聯值的枚舉SportTypeDictionary<SportType, Int32>。你可以簡單地寫val += sportTypeScoreMap[sportType],你就完成了。

這種模式的變化會在很多類似的情況下幫助你。

public enum SportType 
{ 
    Soccer, Football, ... 
} 

public sealed class Foo 
{ 
    private static readonly IDictionary<SportType, Int32> sportTypeScoreMap = 
     new Dictionary<SportType, Int32> 
     { 
      { Soccer, 30 }, 
      { Football, 20 }, 
      ... 
     } 

    private static readonly IDictionary<DayOfWeek, Int32> dayOfWeekScoreMap = 
     new Dictionary<DayOfWeek, Int32> 
     { 
      { DayOfWeek.Monday, 12 }, 
      { DayOfWeek.Tuesday, 20 }, 
      ... 
     } 

    public Int32 GetScore(SportType sportType, DayOfWeek dayOfWeek) 
    { 
     return Foo.sportTypeScoreMap[sportType] 
      + Foo.dayOfWeekScoreMap[dayOfWeek]; 
    } 
} 
+0

比我的更好的語義。 – 2010-06-29 18:44:11

+0

不錯。我可能會使用這樣的東西。但是,我已經擴大了這個問題。看我的編輯。 – 2010-06-29 19:25:22

+0

您將始終達到在通用方法中提取更多功能時不可能(或有用)的地步 - 理想情況下,您必須執行的所有操作都是獨特的,並且不存在通用模式。這種不可壓縮的休息(類比數據壓縮非常適合 - 人們試圖提取所有常見模式,所有仍然看起來像無結構隨機噪聲)仍然可能非常複雜。其餘的最好的方法是用幾個名字很好的小方法儘可能好地模塊化。 – 2010-06-29 23:01:58

0

第一步我可能會打破每個邏輯加工區到它自己的方法(可能不如第一遍最好的名字)

EnforceSportRules 
ProcessSportDetails 
EnforceGenderRules 

下一頁,這取決於如何複雜的規則,我可以將每個部分分成自己的班級,並由主班級(如工廠)進行處理。

GenderRules 
GenderContext 
0

我沒有什麼特別的你提供比先建議不要只是把它作爲一個大block--掰成段,使重要零件之間的分隔註釋。

另一個建議是,如果您要在您的示例中進行很多非常短的測試,請打破常規並將val遞歸器放在與評估和縮進相同的行上,以便它們與對方保持一致。

if (isSoccer)    val = soccerBaseVal; 
if (isMale)    val += 1; 
else      val += 5; 

switch(dayOfWeek){ 
    case DayOfWeek.Monday: val += 12; 
    ... 
} 

多餘的空格可以使那些百點廢成數百行,使垂直滾動過多,難以得到的東西的總體視圖。

1

使用switch語句或filter函數。

通過過濾功能,我的意思是這樣的:

func filter(var object, var value) 
{ 
    if(object == value) 
     object = valueDictionary['value']; 
} 

然後應用濾鏡:

filter(theObject, soccer) 
filter(theObject, football) 

注意過濾效果要好得多,使用字典,但它不是必需的。

+0

你也打敗了我吧。 – 2010-06-29 18:39:03

0

如果你真的只是在這種類型中添加值,我會創建一個具有與數組中存儲的值相對應的已定義索引的枚舉。然後你可以做這樣的事情:

enum Sport 
{ 
    football = 0, 
    soccer = 1, 
    //... 
} 

int sportValues[] = { 
    /* footballValue */, 
    /* soccerValue */, 
    /* ...Values */ 
}; 

int ApplyRules(Sport sport, /* other params */) 
{ 
    int value = startingValue; 
    value += sportValues[(int)sport]; 
    value += /* other rules in same fashion */; 
} 
1

從實用程序員開始討論,你可以使用DSL封裝規則並編寫一個流程引擎。對於您提出的問題,一個解決方案可能是:

MATCH{ 
    Soccer soccerBaseVal 

    IsMale 5 
    !IsMale 1 
} 

SWITCH{ 
    Monday 12 
    Tuesday 13 
} 

然後在比賽的第一個山坳匹配的一切,並在每個第一項SWITCH你來。你可以製作任何你喜歡的語法,然後只需編寫一些腳本來將代碼塞進代碼中(或者使用Xtext,因爲它看起來很酷)。

1

這裏有一些想法:

1使用查找表:

var val = 0; 

SportType sportType = GetSportType(); 

val += sportvalues[sportType]; 

您可以從數據庫中裝載表。

2使用工廠模式:

var val = 0; 

val += SportFactory.Create(sportType).CalculateValue(); 

Dynamic Factory Pattern是在情況下非常有用是新(運動)類型經常被添加到的代碼。此模式使用反射來防止更改工廠類(或任何全局配置)。它允許你簡單地向你的代碼添加一個新類。

當然,動態工廠甚至工廠的使用可能會讓你的情況過度。你是唯一可以說出的人。

0

考慮實施Strategy Pattern,它利用繼承/多態性來管理單個函數。通過將每個功能分成自己的專門課程,您可以放棄擁有數英里長的case區塊或if陳述的噩夢。

不確定C#是否支持它(或者將來),但VB.NET將XML註釋CompletionList指令集成到intellisense中,當它與策略模式結合使用時,可以讓您輕鬆使用Enum面向對象的開放式可擴展性。

相關問題