zoukankan      html  css  js  c++  java
  • Head.First.ObjectOriented.Design.and.Analysis《深入浅出面向对象的分析与设计》读书笔记(四)

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

     引用

         

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

         

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

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

     正文

         

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

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

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

          1、确定(识别)问题

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

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

          2、设计一个解决方案

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

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

          1)主人家的狗叫

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

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

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

    代码
    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;
            }
        }
    }

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

    代码
    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类

    代码
    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

    代码
      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

    代码
     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类来处理,识别器本身不处理,只是根据处理的结果来做出决定。这样就松散了耦合,解耦了识别器类和叫声类。因为其他叫声也很容可以添加进来,否则每一种叫声都必须配备专用的识别器了。

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

          继续上面的分析。

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

         

    代码
    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;
            }
        }
    }

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

    代码
    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中的名词,它们通常就是一个类或者是类中的一个属性;其中的动词通常会是一个类的方法。

    【Blog】http://virusswb.cnblogs.com/

    【MSN】jorden008@hotmail.com

    【说明】转载请标明出处,谢谢

  • 相关阅读:
    libtorch初体验
    libtorch 常用api函数示例(史上最全、最详细)
    VS2015,vs2019用正则表达式搜索删除空白行的方法
    CMake引入opencv3.1.0编译时includes non-existent path问题解决
    opencv编译的时候的注意事项------如果出现 target glog::glog 找不到的情况,可能是由于glog的版本过低导致的。通常与ceres有关
    ID3D11Multithread 未声明的标识符 opencv 411 opencv400 3411 opencv440 vs2015 都出现这个错误 但是opencv311没有出现这个问题
    错误 LNK2001 无法解析的外部符号 "__declspec(dllimport) bool cv::__termination" (__imp_?__termination@cv@@3_NA) opencv_cudev
    raw.githubusercontent.com无法连接
    编译opencv3.1.0时出现错误:error: ‘NppiGraphcutState’ has not been declared
    Ubuntu16.04 安装g++6
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1784437.html
Copyright © 2011-2022 走看看