Head.First.Object-Oriented.Design.and.Analysis《深入浅出面向对象的分析与设计》读书笔记(四)
2010-07-23 23:38 Virus-BeautyCode 阅读(1687) 评论(4) 编辑 收藏 举报
用真实世界检验你的软件-分析 |
引用 |
是时候毕业了,时候去真实世界检验自己的软件了。
上个版本的狗门很是成功,卖的很疯狂。但是越是卖的还要,抱怨就会越多。下面就是一个用户的意见。
“我非常喜欢你的系统,那个语音识别器。但是在我安装了之后,每次邻居家的狗叫的话,门也会自动打开。但是这不是我想要的效果。”
正文 |
你的软件有了一个上下文。到目前为止,我们是在一个真空,没有结合软件运行环境的情况下开发软件。换句话说,我们把软件想象为:运行在完美的世界,在我们预期的情况下运行。每个人都很轻松,周围没有很多条狗。
但是我们的软件终究要运行在真实的世界,而不是一个完美的世界。在真实的世界中,可能会运行错误。周围也会有很多的狗,猫之类的动物。
使得你的软件在真实世界不被搞糟的关键在于分析:在你把软件放到真实世界之前,找出潜在的问题,并且解决这些问题。
1、确定(识别)问题
第一步是找到潜在的问题。我们已经知道,就是邻居家有很多只狗。
使用遥控器没有问题,因为是人工干预。人是可以识别自己家的狗叫的。但是语音识别器好像就差了点,它一听到狗叫就会打开门。意味着,任何一只狗叫都可以打开门。
2、设计一个解决方案
使我们的use case出了问题,在识别器听到狗叫之后没有识别是否是自己家的狗,就打开了门。应该在听到声音之后,需要if判断一下,然后再打开门。
还需要识别器有存储主人家的狗叫声,才可以在收到狗叫之后进行比较。这时候,你就会发现,需要添加一个use case,就是存储狗叫。用例比较简单,就是:
1)主人家的狗叫
2)识别器存储主人家的狗叫声
用例增加之后,就需要我们修改代码。修改的方式有很多种,先看第一种:
在DogDoor中添加一个string类型的字段,用来存储叫声;添加一个方法来设置叫声;添加方法来获取叫声。

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class DogDoor
{
private bool _open;
private string _allowBark;
public void SetAllowBark(string bark)
{
_allowBark = bark;
}
public string GetAllowBark()
{
return _allowBark;
}
public DogDoor()
{
_open = false;
}
public void Open()
{
Console.WriteLine("the dog door opens");
this._open = true;
System.Threading.Thread.Sleep(5000);
Close();
}
public void Close()
{
Console.WriteLine("the dog door closes");
this._open = false;
}
public bool IsOpen()
{
return _open;
}
}
}
另外一种做法就是比较面向对象的程序员写的,新建一个类,定义叫声类

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class Bark
{
private string _sound;
public Bark(string sound)
{
_sound = sound;
}
public string GetSound()
{
return _sound;
}
public override bool Equals(object obj)
{
if (obj is Bark)
{
Bark bark = obj as Bark;
if (bark._sound.Equals(this._sound))
return true;
else
return false;
}
return false;
}
}
}
DogDoor类中的叫声字段的类型则变成了新建的Bark类

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class DogDoor2
{
private bool _open;
private Bark _allowBark;
public void SetAllowBark(Bark bark)
{
_allowBark = bark;
}
public Bark GetAllowBark()
{
return _allowBark;
}
public DogDoor2()
{
_open = false;
}
public void Open()
{
Console.WriteLine("the dog door opens");
this._open = true;
System.Threading.Thread.Sleep(5000);
Close();
}
public void Close()
{
Console.WriteLine("the dog door closes");
this._open = false;
}
public bool IsOpen()
{
return _open;
}
}
}
相应的识别器类中的代码就应该修改为
识别器1

{
Console.WriteLine("Bark Recognizer: heard a "+bark );
if (_door.GetAllowBark().Equals(bark))
_door.Open();
else
Console.WriteLine("this dog is not allow");
}
识别器2

{
Console.WriteLine("Bark Recognizer: heard a " + bark);
if (_door2.GetAllowBark().Equals(bark))
_door.Open();
else
Console.WriteLine("this dog is not allow");
}
识别器2明显好于识别器1,因为在2中将声音比较的任务委托给了bark类来处理,识别器本身不处理,只是根据处理的结果来做出决定。这样就松散了耦合,解耦了识别器类和叫声类。因为其他叫声也很容可以添加进来,否则每一种叫声都必须配备专用的识别器了。
在分析的时候,需要注意需求或者是用例中的名词和动词。名称经常会需要转换成类,或者是类的一个属性。动词则经常会是一个方法。
继续上面的分析。
狗一般不是叫一声,有可能要叫很多声,只要一个声音匹配成功,就应该打开门。识别器需要存储多个狗叫声。

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class DogDoor3
{
private bool _open;
private List<Bark> _allowBark;
public void SetAllowBark(Bark bark)
{
_allowBark.Add( bark);
}
public List<Bark> GetAllowBark()
{
return _allowBark;
}
public DogDoor3()
{
_open = false;
}
public void Open()
{
Console.WriteLine("the dog door opens");
this._open = true;
System.Threading.Thread.Sleep(5000);
Close();
}
public void Close()
{
Console.WriteLine("the dog door closes");
this._open = false;
}
public bool IsOpen()
{
return _open;
}
}
}
这时候识别器就需要修改一下了

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class BarkRecognizer
{
private DogDoor3 _door3;
public BarkRecognizer(DogDoor3 door)
{
_door3 = door;
}
public void Recognize3(Bark bark)
{
Console.WriteLine("Bark Recognizer: heard a " + bark);
foreach (Bark b in _door3.GetAllowBark())
{
if (b.Equals(bark))
{
_door.Open();
return;
}
}
Console.WriteLine("this dog is not allow");
}
}
}
结论 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构