重構
大話重構第二章-針對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展示整個重構過程,難免過度設計,但是隨者業務需求變更複雜,這樣設計是值得。
元哥的筆記