`

Head.First.Object-Oriented.Design.and.Analysis《深入浅出面向对象的分析与设计》读书笔记(四)

阅读更多

 

  

 

  

 用真实世界检验你的软件-分析

 

 引用

     

      是时候毕业了,时候去真实世界检验自己的软件了。

     

      上个版本的狗门很是成功,卖的很疯狂。但是越是卖的还要,抱怨就会越多。下面就是一个用户的意见。

      “我非常喜欢你的系统,那个语音识别器。但是在我安装了之后,每次邻居家的狗叫的话,门也会自动打开。但是这不是我想要的效果。”

 正文

     

      你的软件有了一个上下文。到目前为止,我们是在一个真空,没有结合软件运行环境的情况下开发软件。换句话说,我们把软件想象为:运行在完美的世界,在我们预期的情况下运行。每个人都很轻松,周围没有很多条狗。

      但是我们的软件终究要运行在真实的世界,而不是一个完美的世界。在真实的世界中,可能会运行错误。周围也会有很多的狗,猫之类的动物。

      使得你的软件在真实世界不被搞糟的关键在于分析:在你把软件放到真实世界之前,找出潜在的问题,并且解决这些问题。

      1、确定(识别)问题

      第一步是找到潜在的问题。我们已经知道,就是邻居家有很多只狗。

      使用遥控器没有问题,因为是人工干预。人是可以识别自己家的狗叫的。但是语音识别器好像就差了点,它一听到狗叫就会打开门。意味着,任何一只狗叫都可以打开门。

      2、设计一个解决方案

      使我们的use case出了问题,在识别器听到狗叫之后没有识别是否是自己家的狗,就打开了门。应该在听到声音之后,需要if判断一下,然后再打开门。

      还需要识别器有存储主人家的狗叫声,才可以在收到狗叫之后进行比较。这时候,你就会发现,需要添加一个use case,就是存储狗叫。用例比较简单,就是:

      1)主人家的狗叫

      2)识别器存储主人家的狗叫声

      用例增加之后,就需要我们修改代码。修改的方式有很多种,先看第一种:

      在DogDoor中添加一个string类型的字段,用来存储叫声;添加一个方法来设置叫声;添加方法来获取叫声。

 

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
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;
        }
    }
}

 

      另外一种做法就是比较面向对象的程序员写的,新建一个类,定义叫声类

 

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
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类

 

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
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

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->  public void Recognize(string bark)
        {
            Console.WriteLine(
"Bark Recognizer: heard a "+bark );
            
if (_door.GetAllowBark().Equals(bark))

                _door.Open();
            
else
                Console.WriteLine(
"this dog is not allow");
        }

 

 

 

      识别器2

 

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> public void Recognize(Bark  bark)
        {
            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类来处理,识别器本身不处理,只是根据处理的结果来做出决定。这样就松散了耦合,解耦了识别器类和叫声类。因为其他叫声也很容可以添加进来,否则每一种叫声都必须配备专用的识别器了。

      在分析的时候,需要注意需求或者是用例中的名词和动词。名称经常会需要转换成类,或者是类的一个属性。动词则经常会是一个方法。

      继续上面的分析。

      狗一般不是叫一声,有可能要叫很多声,只要一个声音匹配成功,就应该打开门。识别器需要存储多个狗叫声。

     

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
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;
        }
    }
}

 

       这时候识别器就需要修改一下了

 

代码
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->using System;
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");
        }
    }
}

 

     

     

  结论
      要注意requirements和use case中的名词,它们通常就是一个类或者是类中的一个属性;其中的动词通常会是一个类的方法。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics