在上文中我给出了画图程序的一种最普通也最常见的做法。就是把处理逻辑全放在系统的事件处理函数中,这种方法有以下几个缺点:
1. 逻辑性不强,写到后面自己都绕不过弯来。
2. 一个函数做了太多的事情,复杂的处理逻辑全放在系统的事件处理函数中。
3. 有条件判断,在目前这个简单的应用中还显不出它的可怕,不过它的坏处想想也知道多严重。你可以参考吕震宇的条件外置。
那么,如何才能采取一个有效的方案解决这个问题呢?一步一步来,让我们从重构开始。
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (bDrawLine && bFirstDown)
{
this.Cursor = Cursors.Cross;
Line newLine = new Line();
newLine.StartPoint = new Point(e.X, e.Y);
drawingLine = newLine;
bFirstDown = false;
}
else if (bDrawLine == true && bFirstDown == false)
{
if (drawingLine != null)
{
drawingLine.EndPoint = new Point(e.X, e.Y);
AddLine(drawingLine);
}
this.Cursor = Cursors.Arrow;
}
}
{
if (bDrawLine && bFirstDown)
{
this.Cursor = Cursors.Cross;
Line newLine = new Line();
newLine.StartPoint = new Point(e.X, e.Y);
drawingLine = newLine;
bFirstDown = false;
}
else if (bDrawLine == true && bFirstDown == false)
{
if (drawingLine != null)
{
drawingLine.EndPoint = new Point(e.X, e.Y);
AddLine(drawingLine);
}
this.Cursor = Cursors.Arrow;
}
}
这么多的逻辑,看的太乱了。先使用Extract Method,把条理弄弄清楚。
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (bDrawLine && bFirstDown)
{
RecordFirstPt(e);
bFirstDown = false;
}
else if (bDrawLine == true && bFirstDown == false)
{
RecordSecondPt(e);
bFirstDown = true;
}
}
private void RecordSecondPt(MouseEventArgs e)
{
if (drawingLine != null)
{
drawingLine.EndPoint = new Point(e.X, e.Y);
AddLine(drawingLine);
}
this.Cursor = Cursors.Arrow;
}
private void RecordFirstPt(MouseEventArgs e)
{
this.Cursor = Cursors.Cross;
Line newLine = new Line();
newLine.StartPoint = new Point(e.X, e.Y);
drawingLine = newLine;
}
{
if (bDrawLine && bFirstDown)
{
RecordFirstPt(e);
bFirstDown = false;
}
else if (bDrawLine == true && bFirstDown == false)
{
RecordSecondPt(e);
bFirstDown = true;
}
}
private void RecordSecondPt(MouseEventArgs e)
{
if (drawingLine != null)
{
drawingLine.EndPoint = new Point(e.X, e.Y);
AddLine(drawingLine);
}
this.Cursor = Cursors.Arrow;
}
private void RecordFirstPt(MouseEventArgs e)
{
this.Cursor = Cursors.Cross;
Line newLine = new Line();
newLine.StartPoint = new Point(e.X, e.Y);
drawingLine = newLine;
}
这样主逻辑清楚了许多。
第一次按下鼠标,记录第一个点,然后设为第二种状态,下次再点击的时候,记录第二个点,此时完成一条线段,再回到第一种状态。
两个状态,不错再重构一下。让状态的意思表现出来。
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (IsGetFirstPointState())
{
RecordFirstPt(e);
SetToGetSecondPtState();
}
else if (IsGetSecondPointState())
{
RecordSecondPt(e);
SetToGetFirstPtState();
}
}
private bool IsGetSecondPointState()
{
return bDrawLine == true && bFirstDown == false;
}
private void SetToGetFirstPtState()
{
bFirstDown = true;
}
private void SetToGetSecondPtState()
{
bFirstDown = false;
}
private bool IsGetFirstPointState()
{
return bDrawLine && bFirstDown;
}
{
if (IsGetFirstPointState())
{
RecordFirstPt(e);
SetToGetSecondPtState();
}
else if (IsGetSecondPointState())
{
RecordSecondPt(e);
SetToGetFirstPtState();
}
}
private bool IsGetSecondPointState()
{
return bDrawLine == true && bFirstDown == false;
}
private void SetToGetFirstPtState()
{
bFirstDown = true;
}
private void SetToGetSecondPtState()
{
bFirstDown = false;
}
private bool IsGetFirstPointState()
{
return bDrawLine && bFirstDown;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (bFirstDown == false)
{
if (drawingLine != null)
{
Point mousePoint = new Point(e.X, e.Y);
DrawLine(drawingLine.StartPoint, mousePoint);
}
}
}
{
if (bFirstDown == false)
{
if (drawingLine != null)
{
Point mousePoint = new Point(e.X, e.Y);
DrawLine(drawingLine.StartPoint, mousePoint);
}
}
}
把它也改一下:(具体省略同上)
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (IsGetSecondPointState())
{
DragLine(e);
}
}
{
if (IsGetSecondPointState())
{
DragLine(e);
}
}
通过上面的重构,你对这个画线的过程是否更加清晰了?现在剩下的缺点就在于那个条件判断了。如何把条件判断消除?多态!详见下篇随笔。