理想与现实之间

学习的最好方法就是blog

博客园 首页 新随笔 联系 订阅 管理
 

下面是一个非常简单的例子,也就是Toy Code,不过还是希望能通过这一些简单的代码,来让大家感受一下如何使用抽象来提高程序的扩展能力。

假设我们接到这样一个任务:设计一个类,具有一个能在屏幕上打印出“
Thanks for using this software!"的字样的方法。

 

你可能会首先想到,下面这样简单代码就可以完成这一功能:

 

public class Messenger

{

public void SayThanks()

{

Console.WriteLine("Thanks for using this software!");

}

}

 

而在main函数中的调用代码是这样的:

 

Messenger m = new Messenger();

m.SayThanks();

 

然而你或许会想,如果需求变化了怎么办?万一这个软件出了中文版,老板要求这个方法可以打印中文“谢谢使用本软件”怎么办?我们是不是该在这段程序里预留下一个钩子来防止这种可能?不!完全不必要。这种变化还没有发生,或许这种变化永远也不能会发生。Simple is best.

 

那么接下来让我们看一下如果变化发生了,该如何调整设计,来应对将来所有同类型的变化。

 

假设现在老板要求我们不仅能向控制台输出这段话,还要能向C:\mysoftware.log这个文件输出这段话,这时我们该怎么办呢?你可能会简单地为原来的代码打上个补丁:

 

public class Messenger

{

int type;

public int Type

{

set { type = value; }

get { return type; }

}

public Messenger()

{

type = 0;

}

public Messenger(int t)

{

type = t;

}

public void SayThanks()

{

switch(type)

{

case 0:

Console.WriteLine("Thanks for using this software!");

break;

case 1:

StreamWriter sw = new StreamWriter(@"C:\mysoftware.log",true);

sw.WriteLine("Thanks for using this software!");

sw.Flush();

sw.Close();

break;

}

 

}

}

 

简单地加上一个type,然后用上一个switch就把这个问题解决了,甚至为了尽量少改变原有代码,我们重载了构造函数,这样原来的代码不加改变的话仍然是默认地向控制台输出,而新添的代码想要向文件输出的只要设置一下type的值就可以了。难道这样的代码不完美吗?

 

然而,如果下次老板要求输出成XML文件,甚至输出到Socket时,我们不得不再次来改动Messenger类的实现代码。而我们已经为了输出至文件改变了原有的设计,为什么不优化一下设计,使得面对这一类型的都变得方便呢?理想的状况应该是增加新的功能应该只要求增加新的代码,而不改变原有的代码。

 

所有问题的解决方案就在于“抽象”。我们可以看出来以上这几个变化的共同点是都要输出一段文字,不同的是输出的方式,这就让我们想到要定义一个接口来表达这种共同点。

 

public interface IMessageSender

{

void SendMessage(string content);

}

 

定义这样一个接口,然后让Messenger类来使用这个接口的实现类来发送消息:

 

public class Messenger

{

public Messenger()

{

itsSender = new ConsoleMessageSender();

}

 

private IMessageSender itsSender;

 

public IMessageSender Sender

{

set { itsSender = value; }

}

 

public void SayThanks()

{

itsSender.SendMessage("Thanks for using this software!");

}

}

 

并分别定义从Console输出和向文件输出的两个类就可以了:

 

public class ConsoleMessageSender : IMessageSender

{

public void SendMessage(string content)

{

Console.WriteLine(content);

}

}

 

public class FileMessageSender : IMessageSender

{

public void SendMessage(string content)

{

StreamWriter sw = new StreamWriter(@"C:\mysoftware.log", true);

sw.WriteLine("Thanks for using this software!");

sw.Flush();

sw.Close();

}

}

 

下次,面对输出至XML这样的需求变化时,我们只要简单地增加一个IMessageSender的子类就可以了。用这种方式我们彻底解决了这一类型的需求变化。

posted on 2004-09-11 21:43  Justin Shen  阅读(1065)  评论(5编辑  收藏  举报