天天看點

C# - 代碼重構

隐藏更多

隻暴露集合中供人使用的單一功能,将關于集合的更多功能隐藏掉。

舊版本

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的方法,它沒有索引器,是以它隻能提供一個枚舉器供使用者調用,進而防止了集合元素被修改的可能。

C# - 代碼重構
C# - 代碼重構

新版本

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# - 學習總目錄

下一篇: 練習39