我们假设要建立一个软件搜索系统,UML类图如下:
此时,用户需求大致如下:
建立一个已有软件的软件列表,并且可以通过软件类型,搜索出全部相应的软件并输出之。
于是,根据用户的需求,我们建立了Software和SoftwareList两个类:
{
public Software(string id, string name, string version, string type)
{
_id = id;
_name = name;
_version = version;
_type = type;
}
private string _id;
public string Id
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _version;
public string Version
{
get { return _version; }
set { _version = value; }
}
private string _type;
public string Type
{
get { return _type; }
set { _type = value; }
}
public override string ToString()
{
return string.Format("Software No.{0}: {1}, Ver.{2} belongs to {3}.\n", new string[] { _id, _name, _version, _type });
}
}
class SoftwareList
{
List<Software> _softwares;
public SoftwareList()
{
_softwares = new List<Software>();
}
public void AddSoftware(string id, string name, string version, string type)
{
Software sw = new Software(id, name, version, type);
_softwares.Add(sw);
}
public List<Software> SearchSoftware(Software softwareToSearch)
{
List<Software> result = new List<Software>();
foreach (Software currentSoftware in _softwares)
{
//只对比类型,过滤出符合用户要求的软件
if (currentSoftware.Type.ToLower() == softwareToSearch.Type.ToLower())
{
result.Add(currentSoftware);
}
}
return result;
}
}
{
static void Main(string[] args)
{
SoftwareList softwares=new SoftwareList();
InitSoftList(softwares);
//The Searcher knows only type of the software he wanna
Software softwareToSearch=new Software("","","","tools");
List<Software> result = softwares.SearchSoftware(softwareToSearch);
if (result.Count > 0)
{
Console.WriteLine("There're the software you are interested in:\n");
foreach (Software soft in result)
{
Console.WriteLine(soft.ToString());
}
}
else
{
Console.WriteLine("Sorry, there's nothing you are interested in.");
}
Console.WriteLine("Press any key to continue");
Console.ReadKey(true);
}
private static void InitSoftList(SoftwareList softwares)
{
softwares.AddSoftware("1", "WinRAR", "3.70", "Tools");
softwares.AddSoftware("2", "Windows", "Vista", "OS");
softwares.AddSoftware("3", "Thunder", "5.6.9", "Tools");
}
}
运行它,会出现我们期望的结果,它似乎工作得很好。
但是,其实目前的设计中存在着很大的问题。问题在哪儿呢?突然有一天,痛苦的事情发生了:用户说,再给软件加一个“语言”属性,来标识该软件是什么语言的,例如中文啊、英文……很好,看来我们得给Software类加上一个语言属性。这时,问题来了,天哪,看来,我们还不得不修改我们的SoftwareList类,修改它的AddSoftware方法和SearchSoftware方法。也许,对于这样子一个小程序来说,这样的修改算不了什么,但是,在大型项目中,这样的设计导致的后果将是不堪设想的。一个类的修改影响到另外一个甚至多个类,那么,在一个拥有几十个类的项目里,这种修改的毁灭性的“效果”是可想而知的。
如何来避免这种灾难?其实,方法也很简单,只要把一个类的可变部分抽取成新的类即可。看看我们怎么修改我们的设计。
首先,第一步,把Software类里的可变部分抽取出来,形成一个新类:
{
public SoftwareSpecific(string type, string language)
{
_type = type;
_language = language;
}
private string _type;
public string Type
{
get { return _type; }
set { _type = value; }
}
private string _language;
public string Language
{
get { return _language; }
set { _language = value; }
}
}
然后,修改原来的Software类,把变动属性从原来的类中去除,并添加特征类实例:
{
public Software(string id, string name, string version, SoftwareSpecific sSpec)
{
_id = id;
_name = name;
_version = version;
//_type = type;
_sSpec = sSpec;
}
private SoftwareSpecific _sSpec;
public SoftwareSpecific Specific
{
get { return _sSpec; }
}
private string _id;
public string Id
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _version;
public string Version
{
get { return _version; }
set { _version = value; }
}
//private string _type;
//public string Type
//{
// get { return _type; }
// set { _type = value; }
//}
public override string ToString()
{
return string.Format("Software No.{0}: {1}, Ver.{2} belongs to {3} and in language {4}.\n", new string[] { _id, _name, _version, _sSpec.Type, _sSpec.Language });
}
}
最后,修改SoftwareList类:
{
List<Software> _softwares;
public SoftwareList()
{
_softwares = new List<Software>();
}
public void AddSoftware(Software s)
{
//Software sw = new Software(id, name, version, type);
_softwares.Add(s);
}
public List<Software> SearchSoftware(SoftwareSpecific ssp)
{
List<Software> result = new List<Software>();
foreach (Software currentSoftware in _softwares)
{
//只对比类型,过滤出符合用户要求的软件
if (currentSoftware.Specific.Type.ToLower() != ssp.Type.ToLower()) continue;
//添加对比语言,以找出符合用户要求的软件
if (currentSoftware.Specific.Language.ToLower() != ssp.Language.ToLower()) continue;
result.Add(currentSoftware);
}
return result;
}
}
哈哈,一个新的程序,添加了语言属性的新程序,又可以正常的运行了。下次要添加属性时,就不会再牵涉到除了SoftwareSpecific类以外的类了。呵呵,这就是把变动部分抽取成新类的方法。
等等,重新看一下代码,真的不需要改其它代码了?哦~,看看SoftwareList类的SearchSoftware方法吧,这里只进行了Type和Language的比较,如果下次添加了一个新的属性,岂不是又要添加一条语句?有没有好的办法来解决这个问题?呵呵,其实很简单,重载一下SoftwareSpecific类的Equals方法,就可以解决问题。我们来看代码片断:
{
SoftwareSpecific right = obj as SoftwareSpecific;
if (this._language.ToLower() != right._language.ToLower()) return false;
if (this._type.ToLower() != right._type.ToLower()) return false;
return true;
}
{
List<Software> result = new List<Software>();
foreach (Software currentSoftware in _softwares)
{
if (currentSoftware.Specific.Equals(ssp))
{
result.Add(currentSoftware);
}
}
return result;
}
经过这么一翻折腾,终于使得我们在今后要添加更多属性时可以变得轻而易举了。
呵呵,初涉OOA&D,文章写得不好。欢迎有兴趣的朋友留言讨论啊。
Little knowledge is dangerous.