重構學習筆記(2)-大話重構第二章-針對HelloWorld抽取類別和介面-筆記

重構

大話重構第二章-針對HelloWorld抽取類別和介面-筆記

重構方法會分幾個層次

  • 方法重構
  • 物件重構
  • 物件之間重構
  • 繼承體系間重構
  • 組織資料的重構
  • 體系架構的重構

在第一篇的是專門講提取方法,但這一支程式有一個狀況是有內聚上的問題。
原程式如下:

    /// <summary>
    /// The Refactoring's Hello-world program
    /// author eddie
    /// </summary>
    public class HelloWorld
    {
        /// <summary>
        /// Say hello to everyone
        /// </summary>
        /// <param name="now"></param>
        /// <param name="user"></param>
        /// <returns>
        /// the words what to say
        /// </returns>
        public string sayHello(DateTime now, string user)
        {
            int hour = getHours(now);
            return "Hi, " + user + "." + getSecondGreeting(hour); ;
        }
        /// <summary>
        /// Get current hour of day
        /// </summary>
        /// <param name="now"></param>
        /// <returns>
        /// current hour of day
        /// </returns>
        private int getHours(DateTime now)
        {
            Calendar calendar = new Calendar();
            calendar.setTime(now);
            return calendar.get(calendar.HOUR_OF_DAY);
        }
        /// <summary>
        /// Get the second greeting.
        /// </summary>
        /// <param name="hour"></param>
        /// <returns>
        /// the second greeting
        /// </returns>
        private  string getSecondGreeting(int hour)
        {
            if (hour >= 6 && hour < 12)
                return "Good morning!";
            else if (hour > 12 && hour < 19)
                return "Good afternoon!";
            else
                return  "Good night!";
        }

    
    }

    internal class Calendar
    {
        public DateTime HOUR_OF_DAY;

        internal void setTime(DateTime now)
        {
            HOUR_OF_DAY = now;
        }
        public int get(DateTime hour_of_day)
        {
            return HOUR_OF_DAY.Hour;
        }
    }

接者開始進行重構,將getHour()用DateUtil管理以及Greeting管理各種問候語…

    /// <summary>
    /// A utility about time.
    /// </summary>
    public class DateUtil
    {
        /// <summary>
        /// Get current hour of day.
        /// </summary>
        /// <param name="now"></param>
        /// <returns>
        /// current hour of day
        /// </returns>
        public int getHours(DateTime now)
        {
            Calendar calendar = new Calendar();
            calendar.setTime(now);
            return calendar.get(calendar.HOUR_OF_DAY);
        }
    }
	/// <summary>
    /// All kinds of greeting.
    /// </summary>
    public class Greeting
    {
        /// <summary>
        /// Get the first greeting.
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string getFirstGreeting(string user)
        {
            return "Hi, " + user + ".";
        }

        /// <summary>
        /// Get the second greeting.
        /// </summary>
        /// <param name="hour"></param>
        /// <returns>
        /// return if in the morning,say  "Good morning!",</para> 
        /// if in the afternoon, say "Good afternoon!"</para> 
        /// , else say "Good night!". 
        /// </returns>
        public string getSecondGreeting(int hour)
        {
            if (hour >= 6 && hour < 12)
                return "Good morning!";
            else if (hour > 12 && hour < 19)
                return "Good afternoon!";
            else
                return "Good night!";
        }

    }
    /// <summary>
    /// The Refactoring's Hello-world program
    /// author eddie
    /// </summary>
    public class HelloWorld
    {
        /// <summary>
        /// Say hello to everyone.
        /// </summary>
        /// <param name="now"></param>
        /// <param name="user"></param>
        /// <returns>
        /// the words what to say
        /// /// </returns>
        public string sayHello(DateTime now, string user)
        {
            var dateUtil = new DateUtil();
            int hour = dateUtil.getHours(now);
            var greeting = new Greeting();
            return greeting.getFirstGreeting(user) + greeting.getSecondGreeting(hour); ;
        }
    }
  • getHour()從HelloWorld類別抽離出來,放到DateUtil
  • getFirstGreeting()與getSecondGreeting(),放到Greeting 這種做法叫做【提取類別】(Extract Class)

觀察以下的程式碼,若是這一段需求一直追加狀況下,目前有morning,afternoon,night若追加程式碼狀況下,擴展性就會不好。

 

        /// <summary>
        /// Get the second greeting.
        /// </summary>
        /// <param name="hour"></param>
        /// <returns>
        /// return if in the morning,say  "Good morning!",</para> 
        /// if in the afternoon, say "Good afternoon!"</para> 
        /// , else say "Good night!". 
        /// </returns>
        public string getSecondGreeting(int hour)
        {
            if (hour >= 6 && hour < 12)
                return "Good morning!";
            else if (hour > 12 && hour < 19)
                return "Good afternoon!";
            else
                return "Good night!";
        }

開始進行做IGreetingRule 介面,分別寫MorningGreeting、AfternoonGreeting、NightGreeting。

    /// <summary>
    /// Greeting roules interface
    /// </summary>
    public interface IGreetingRule
    {
        bool isRight(int hour);
        string getGreeting();
    }
    /// <summary>
    /// The greeting in the morning
    /// </summary>
    public class MorningGreeting : IGreetingRule
    {
        public string getGreeting()
        {
            return "Good morning!";
        }

        public bool isRight(int hour)
        {
            return (hour >= 6 && hour < 12);
        }
    }
    /// <summary>
    /// The greeting in the afternoon
    /// </summary>
    public class AfternoonGreeting : IGreetingRule
    {
        public string getGreeting()
        {
            return "Good afternoon!";
        }

        public bool isRight(int hour)
        {
            return (hour >= 12 && hour < 19);
        }
    }
    /// <summary>
    /// The greeting in the night
    /// </summary>
    public class NightGreeting : IGreetingRule
    {
        public string getGreeting()
        {
            return "Good Night!";
        }

        public bool isRight(int hour)
        {
            return hour > 18;
        }
    }   

回頭調整Greeting的程式

    public class Greeting
    {
        /// <summary>
        /// Get the first greeting.
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string getFirstGreeting(string user)
        {
            return "Hi, " + user + ".";
        }
        /// <summary>
        /// Get the second greeting.
        /// </summary>
        /// <param name="hour"></param>
        /// <returns>
        /// return if in the morning,say  "Good morning!",</para> 
        /// if in the afternoon, say "Good afternoon!"</para> 
        /// , else say "Good night!". 
        /// </returns>
        public string getSecondGreeting(int hour)
        {
            IGreetingRule[] greetingRules = new IGreetingRule[]
            {
                new MorningGreeting(),
                new AfternoonGreeting(),
                new NightGreeting()
            };
            foreach (var greetingRule in greetingRules)
            {
                if (greetingRule.isRight(hour))
                    return greetingRule.getGreeting();
            }
            throw new Exception("Error when greeting!");
        }
    }

這種做法叫做【提取介面】(Extract Interface)

上述例子只是展示重構的過程,從HelloWorld展示整個重構過程,難免過度設計,但是隨者業務需求變更複雜,這樣設計是值得。

重構

元哥的筆記