1. 程式人生 > >C# - 代碼重構

C# - 代碼重構

多功能 語句 sta 數據 應對 ted ces roc 不同

隱藏更多

只暴露集合中供人使用的單一功能,將關於集合的更多功能隱藏掉。

舊版本

public class Animal
{
private List<string> LanguageList = new List<string>
{
"#$%^",
"@*&#",
"中文",
"英文"
};

public IList<string> GetLanguageList( )
{
return LanguageList;
}
}

public class
Programe

{
static void Main( string[] args )
{
Animal a = new Animal( );
var language = a.GetLanguageList( );
language[0]=
}
}

IList<T>具有索引器,可以通過數組檢索的方式設置元素的值,而我們只想讓用戶調用枚舉器對集合進行簡單的叠代或查詢,但並不需要他們插手對集合元素的值的更改。所以此時就要考慮讓GetLanguageList方法返回一個IEnumerable<T>,由於IEnumerable<T>只有一個GetEnumerator的方法,它沒有索引器,所以它只能提供一個枚舉器供用戶調用,從而防止了集合元素被修改的可能。

技術分享圖片技術分享圖片

新版本

public IEnumerable<string> GetLanguageList( )
{
return LanguageList; //方法返回的LanguageList隱式轉換為了IEnumerable<string>
}

提升成員

將完全重名的字段、屬性、方法提升到基類,供每個子類調用。

聚合模擬多繼承

為了使沒有邏輯上的繼承關系的兩個類強行發生關系,可以將其中一個類作為另一個類的成員來存取。

抽象解耦

如果其它類需要與某個類(x)發生關系,則可以將x類抽象成一個接口,將其成員抽象到接口中,其它類只需要和接口發生關系,而不需要直接與x發生關系,好處在於如果今後刪除了x,我們還可以創建y類來實現接口,這樣就不會影響與接口發生關系的那些類。接口就像角色那樣,x具有這個角色所要求的的功能,所以x=此角色,y具有這個角色所要求的的功能,那麽y也=此角色,對於其它想要與x發生 關系的那些類來說,它們完全可以只需要與角色發生關系,而不用在乎這個角色是由誰來扮演,所以如果x後來死掉了,它們是不用感到驚慌失措的,因為它們只關心和其發生關系的角色。

用屬性替代字段

關鍵思路:多使用屬性,少用字段。因為字段過於粗略,而屬性由於多了兩個方法塊,就可以提供更精細的操作邏輯,在設置或獲取數據之前你就可以編碼出更多的細節控制。

常量封裝

如果一些頻繁使用的常量總是存在於方法的代碼塊中,假如有100個方法都在使用這些常量,而今後需求變更,需要更改這個常量值,你就需要把存在於100個方法中的這個常量值給修改掉,工作量巨大而且毫無樂趣,簡單的辦法就是,將這種普遍存在於各個方法中的常量封裝成一個方法的返回值抑或封裝到枚舉中以應對將來可能發生的需求變更,需求變更時,只需要在封裝的方法裏或枚舉中修改這個常量值即可。

方法分割

如果一個方法中的邏輯代碼過於臃腫,就很難讓人去嘗試閱讀,也不方便調試,更不利於需求變更時的代碼修改,方法應該作為一個單一的功能供其它方法調用,所以,將一個有N個操作邏輯的方法分割成多個方法,每個方法只提供一個單一的功能,這樣就更便於閱讀、理解和修改。

封裝條件

如果一個條件判斷中有多個條件,這會使代碼難以閱讀,將條件的邏輯判斷封裝成望文即可生義的屬性或方法後,只需要使用屬性或方法做判斷即可。如果條件需要用某個參數做判斷則把判斷的邏輯定義成方法,否則定義成屬性即可。

舊版

public class Test
{
public void Show( string arg )
{
if (arg.Trim( new char[] { ‘u‘, ‘p‘ } ).Length > 10 && arg.Contains( "s" ) && arg.LastIndexOf( "a" ) != -1) { }
if (DateTime.Now.Hour == 12 && DateTime.Now.DayOfWeek == DayOfWeek.Monday && DateTime.Now.DayOfYear == 1984) { }
}
}

新版

public class Test
{
public bool IsArgPass( string arg ) { return arg.Trim( new char[] { ‘u‘, ‘p‘ } ).Length > 10 && arg.Contains( "s" ) && arg.LastIndexOf( "a" ) != -1; }
public bool IsNowTimePass { get { return DateTime.Now.Hour == 12 && DateTime.Now.DayOfWeek == DayOfWeek.Monday && DateTime.Now.DayOfYear == 1984; } }
public void Show( string arg )
{
//望文生義,IsArgPass表示參數是否通過測試
if (IsArgPass( arg )) { }
//望文生義,IsDatimePass表示當前時間是否正確
if (IsNowTimePass) { }
}
}

移除條件

如果一個類需要根據條件調用不同的方法,假如有100個條件就需要判斷100次。這樣就降低了代碼的復用性和靈活性。為此,可以使用一個簡單的策略,將條件作為哈希字典的key,將對應的方法作為哈希字典的Value,當用戶傳遞一個條件到類中,類只需要從哈希字典去取出Key所對應方法即可。

舊版本

//國籍
public enum Country { UnitedKingdom = 1 << 1, Japan = 1 << 2, China = 1 << 3 }

//語言
public class Language
{
public void UnitedKingdomLanguage() { Console.WriteLine( "hello" ); }
public void JapanLanguage( ) { Console.WriteLine( "ハロー" ); }
public void ChinaLanguage( ) { Console.WriteLine( "你好" ); }
}

//服務
public class Service
{
private Language Language = new Language( );
//根據國籍提供不同版本的語言對話
public void ShowLanguage( Country country )
{
switch (country)
{
case Country.Japan:
Language.JapanLanguage( );
break;
case Country.China:
Language.ChinaLanguage( );
break;
case Country.UnitedKingdom:
Language.UnitedKingdomLanguage( );
break;
}
}
} Service service = new Service( );
service.ShowLanguage( Country.Japan );

新版本

//國籍
public enum Country { UnitedKingdom = 1 << 1, Japan = 1 << 2, China = 1 << 3 }

//語言接口
public interface ILanguage
{
void UnitedKingdomLanguage( );
void JapanLanguage( );
void ChinaLanguage( );
}

//語言
public class Language:ILanguage
{
public void UnitedKingdomLanguage() { Console.WriteLine( "hello" ); }
public void JapanLanguage( ) { Console.WriteLine( "ハロー" ); }
public void ChinaLanguage( ) { Console.WriteLine( "你好" ); }
}

//服務
public class Service
{
private ILanguage Language;
private Dictionary<Country,Action> LanguageMethodDictionary { get; set; }
public Service( ILanguage language )
{
this.Language = language;
LanguageMethodDictionary = new Dictionary<Country, Action>
{
{ Country.China, Language.ChinaLanguage },
{ Country.Japan, Language.JapanLanguage },
{ Country.UnitedKingdom, Language.UnitedKingdomLanguage },
};
}

//根據國籍提供不同版本的語言對話
public void ShowLanguage( Country country )
{
LanguageMethodDictionary[country]( );
}
} Service service = new Service( new Language() );
service.ShowLanguage( Country.Japan );

盡早返回

如果一個方法中有大量的條件分支語句,這會使得整個邏輯走向變得不清晰,最佳做法是盡早return,把不滿足條件的情況盡早返回,這樣可以使代碼更容易理解和閱讀。

  

  

C# - 學習總目錄

C# - 代碼重構