在上一篇文章中我們把目標倒是定好了,從哪兒開始呢:去掉可惡的if和switch語句、去掉重複語句,還是減少那些長方法的行數?這是個問題,也許唯一能確定的就是先不去碰那個“8像素”限制了。
仔細分析代碼,我們會發現導致這個控制項中代碼高重複率的主要原因在於大大量使用了if和switch。進一步分析,編CollapsibleSplitter兄弟為什麼會使用這麼多分支語句呢?是這麼這麼這麼的…嘿嘿J:
- 此控制項支援五種繪製風格(分別是Mozilla、XP、Win9x、DoubleDots和Lines),代碼需要判斷使用者選擇的是那一種風格;
- 此控制項支援四種停靠方式(分別是Top、Bottom、Left和Right),代碼需要判斷使用者選擇的是那一種停靠方式;
- 在繪製介面、控制行為的時候控制項會在多種狀態中來回變換。
物件導向語言使用什麼來代替這些分支語句?把問題放到腦子裡轉兩圈——嗯,是策略模式(Strategy)和狀態機器模式(State)。好吧,那下面就使用這兩個模式來進行我們的除臭工作吧。
開始前我們先來溫習一下這兩個模式(從《設計模式迷你手冊》中摘取):
Strategy模式
State模式
我們先定義風格系列“策略”。依據方向(橫向或縱向)的不同,繪製介面風格的代碼也頗為不同,因此我們為基類定義兩個不同的繪製函數,分別代表橫向繪製和縱向繪製。下面是抽象基類VisualStyle和及其Mozilla繪製風格的子類:
namespace ISAK.WinGui.Controls.Styles
{
abstract class VisualStyle
{
public abstract void DrawVertical(Graphics g, int x, int y, Color lineColor);
public abstract void DrawHorizontal(Graphics g, int x, int y, Color lineColor);
}
class VisualStyleMozilla: VisualStyle
{
public override void DrawVertical(Graphics g, int x, int y, Color lineColor)
{
for (int i = 0; i < 30; i++)
{
// light dot
g.DrawLine(new Pen(SystemColors.ControlLightLight), x, y + (i * 3), x + 1, y + 1 + (i * 3));
// dark dot
g.DrawLine(new Pen(SystemColors.ControlDarkDark), x + 1, y + 1 + (i * 3), x + 2, y + 2 + (i * 3));
// overdraw the background color as we actually drew 2px diagonal lines, not just dots
g.DrawLine(new Pen(lineColor), x + 2, y + 1 + (i * 3), x + 2, y + 2 + (i * 3));
}
}
public override void DrawHorizontal(Graphics g, int x, int y, Color lineColor)
{
for (int i = 0; i < 30; i++)
{
// light dot
g.DrawLine(new Pen(SystemColors.ControlLightLight), x + (i * 3), y, x + 1 + (i * 3), y + 1);
// dark dot
g.DrawLine(new Pen(SystemColors.ControlDarkDark), x + 1 + (i * 3), y + 1, x + 2 + (i * 3), y + 2);
// overdraw the background color as we actually drew 2px diagonal lines, not just dots
g.DrawLine(new Pen(lineColor), x + 1 + (i * 3), y + 2, x + 2 + (i * 3), y + 2);
}
}
}
}
其他繪製風格的子類還有VisualStyleXP、VisualStyleWin9x、VisualStyleDoubleDots、VisualStyleLines,其代碼也是直接從OnPaint方法中的相關位置拷貝過去的。
接著,我們為CollapsibleSplitter類添加一個私人成員
private Styles.VisualStyle styleDrawer;
然後,我們修改VisualStyle屬性的set方法:>
public VisualStyles VisualStyle
{
get{ return this.visualStyle; }
set
{
this.visualStyle = value;
switch (value)
{
case VisualStyles.Mozilla:
styleDrawer = new Styles.VisualStyleMozilla();
break;
case VisualStyles.XP:
styleDrawer = new Styles.VisualStyleXP();
break;
case VisualStyles.Win9x:
styleDrawer = new Styles.VisualStyleWin9x();
break;
case VisualStyles.DoubleDots:
styleDrawer = new Styles.VisualStyleDoubleDots();
break;
case VisualStyles.Lines:
styleDrawer = new Styles.VisualStyleLines();
break;
}
this.Invalidate();
}
}
再把OnPaint方法中的兩個switch去掉,上邊的那switch系列的一大堆代碼改成下面的樣子
styleDrawer.DrawVertical(g, x, y, hot ? hotColor : BackColor);
下面那switch系列的一大堆代碼改成>
styleDrawer.DrawHorizontal(g, x, y, hot ? hotColor : BackColor);
這繪製風格方面的臭味算是暫且搞定了,雖尚有些令人不滿意的地方(看看上面的兩個hot ? hotColor : BackColor),但還算過得去。嘿嘿,有些細微的工作麼,留待最後才搞定好了。