面向对象分析设计学习与探索(五):分析(Analysis)
在开发的过程中,我们所写的程序如同在真空中一样,相对理想的环境,相对较好的机器。然而一旦软件部署到客户端,软件就在现实世界中工作。此时,很多性能和并发的问题就产生了。
让软件在真实的世界中正常工作的关键是分析:在发布你的程序前,指出潜在的问题,然后解决他们。分析帮助你确保你的系统在现实环境中工作。
分析的第一步就是:指出潜在的问题:
回到上一章的故事,还记得那个改进后的Dog Door。现在有了一个新的问题:邻居家的狗叫的时候,这个门也会自动打开。
现在问题发现了,根据问题要重新修改用例。接收到声音信号后,BarkRecognizer要识别是否是这家人的小狗叫。修改后用例如下:(黑色粗体为修改的部分)
从用例中我们可以看出,现在声音识别器在获得音频信号后,要进行比对,以确认这个声音是否为此家人的小狗。这样,我们就要保存一个小狗的声音用来比对。所以我们需要一个新的用例来保存狗的叫声。
用例更新后,程序需要做相应的修改,但是有一个问题出现:如何更改。实际上程序有很多实现方式。如何选择?
有人认为:简单是最好的。既然需要一个对象存储小狗的叫声,当需要的时候进行比对,那我们可以用一个String对象来存储。只需要在Dog Door 对象中进行修改。代码修改如下:
public class DogDoor
{
private String _allowedBark;
public String AllowedBark
{
get { return _allowedBark; }
set { _allowedBark = value; }
}
//
}
相应的BarkRecognizer()中也需要修改:
public class BarkRecognizer
{
DogDoor door = new DogDoor();
public void recognizer(String Bark)
{
if (door.AllowedBark == Bark)
{
door.Open();
}
}
//
}
也有人更忠实于面向对象。在这种情况下,编写一个Bark类型,并赋予相应的比较方法。添加Bark类型:
public class Bark
{
private String _sound;
public Bark(String sound)
{
_sound = sound;
}
public String Sound
{
get { return _sound; }
}
public Boolean Equal(Bark bark)
{
Boolean flag = false;
if (bark._sound == _sound)
{
flag = true;
}
return flag;
}
}
当然,Dog Door类型也需要修改,代码如下:
public class DogDoor
{
private Bark _allowedBark;
public Bark AllowedBark
{
get { return _allowedBark; }
set { _allowedBark = value; }
}
//
}
BarkRecognizer类型中的修改如下:
public class BarkRecognizer
{
DogDoor door = new DogDoor();
public void recognizer(Bark Bark)
{
if (door.AllowedBark.Equal(Bark))
{
door.Open();
}
}
//
}
那么哪一种方式更好呢?在这里要提到一个问题:解耦合。也就是说,你的对象对于其他的对象是独立的,或者说一个对象的变化不会导致其他对象的变化。书中写道:Delegation helps our applications stay loosely couples。意思是说:Delegation帮助我们的程序保持松耦合,对于Delegation的翻译,我一直觉得是代理。但在这里我感觉是封装的意思,不知我的理解是否正确。回到刚才两个方法的讨论:如果对于小狗的叫声存储的是声音文件,比如说WAV,对于第二种方式我们只需要修改Bark类型中的Equal方法就可以,BarkRecognizer类型中不需要修改。Delegation shields your object from implementation changes to other objects in your softwave。但是现在又出现一个很实际的问题:小狗的叫声可能有很多种,无论哪一种,我们应该让门打开。那么在DogDoor类型中的AllowedBark应该是一组Bark对象,换句话说:AllowedBark应该是List<Bark>类型。
说到这里,一个疑惑出现了,如何确定一个程序中的类型?注意用例中的名词。用例中的名词往往是你系统中所需要实现的类型。那么现在把用例中的名词圈出来。
不难看出,很多名词是系统中需要的类型。当然也有些名词是不需要注意的,如;button owner outside inside
书中提到一个词:textual analysis 文本分析。
Looking at nouns and verbs in your use case to figure out classes and methods is called textual analysis.
回到用例中,注意用例中的第三步:3.If it’s the owner’s dog barking. The bark recognizer sends a request to the door open. Owner’s dog是一个名字,但是我们不需要为dog创建一个类型,因为他是发起者,在系统之外。对于Bark,不要只把关注点放到Bark上,还要注意是the owner’s dog。
对于用例中的动词,实际上是系统重要实现的方法。
完成分析后,明确了系统中需要的类型和方法,我们可以很简单的画出系统的类图。类图中可以描述类型之间的依赖关系。
分析得差不多了,类图也画出来了。虽然类图可以很清楚的表现出类型之间的关系,但是不能告诉我们代码是如何实现的。下面我们来看看代码的实现:
首先编写Bark类型
public class Bark
{
private String _sound;
public Bark(String sound)
{
_sound = sound;
}
public String Sound
{
get { return _sound; }
}
public Boolean Equal(Bark bark)
{
Boolean flag = false;
if (bark._sound == _sound)
{
flag = true;
}
return flag;
}
}
在DogDoor类型中加入如下代码:
private List<Bark> _allowedbarks;
public List<Bark> AllowedBarks
{
get { return _allowedbarks; }
set { _allowedbarks = value; }
}
修改BarkRecognizer中的recognize方法,代码如下:public void recoginze(Bark bark)
{
Console.WriteLine(" BarkRecognizer heard a '" + bark.Sound + "'");
foreach (Bark allowbark in _door.AllowedBarks)
{
if (bark.Equal(allowbark))
{
_door.Open();
break;
}
else
{
continue;
}
}
}
最后修改测试代码并查看结果:
static void Main(string[] args)
{
DogDoor door = new DogDoor();
door.AllowedBarks.Add(new Bark("Woof"));
door.AllowedBarks.Add(new Bark("Yip"));
BarkRecognizer recognizer = new BarkRecognizer(door);
Remote remote = new Remote(door);
Console.WriteLine("The dog is barking, he wanna ");
Bark bark1 = new Bark("Woof");
recognizer.recoginze(bark1);
Console.WriteLine("The dog is outside and ");
Thread.Sleep(10000);
Bark bark2 = new Bark("Yip");
Console.WriteLine("The dog is barking, he wanna inside");
recognizer.recoginze(bark2);
Console.WriteLine("The dog is inside");
Thread.Sleep(10000);
Console.WriteLine("Another dog is barking");
Bark bark3 = new Bark("Hooh");
recognizer.recoginze(bark3);
Console.Read();
}
输出结果为: