KiddLee

态度决定一切!我博客,留住生活中的精彩
数据加载中……
面向对象分析设计学习与探索(四):需求变化(Requirements Change)

        需求变化往往是一个项目中不可避免的,当然也是常常是使开发者头痛的。用户在使用软件后常常会出现这样或那样的想法。目前的软件虽然已经满足了他们先前提出的要求。但是要知道,结束意味着新的开始。还记得上一篇文章中的那个客户吗?他们又回来了!
        上一篇中我们为他们开发了一个Dog Door。在使用中都很好,但现在他们有了一些新的建议。他们常常乱放遥控器,以至于当小狗要出去或者近来时,不得不去找一下遥控器放在那里了。(有点头大,但是用户往往是对的,需求经常变化即使你有一个好的用例,你常常要快速改变你的软件以适应那些新的需求。)
        根据他们的需求,我们需要相应的修改我们的用例:看到需求后,感觉我们只需要在小狗barking的时候加一个声音识别装置来接收声音信号,然后再开门。

                

        看了这个用例的确让人疑惑,因为新加入的步骤让人觉得比较混乱。当用例让我们疑惑时,我们需要重写用例。上面用例的问题在于新加入的步骤并不是一个子步骤或者是一个先后的顺序,而是并列的关系。而且根据上面的需求,客户希望Dog Door主动识别小狗的叫声并开门,而不再过多地依靠他们。那好,用例应该是这样的:

                

        注意:现在加了两个标签,Main Path & Alternate Paths
        Main Path:我理解为在一般的情况下都会发生的途径,或者说主要发生的途径
        Alternate Paths:我理解为有可能发生的途径,替代途径
        对于一个用例来说,从开始到结束可能有很多的途径,这时有一个scenario概念出现,可以理解为一个场景或者一种可能发生的途径。书上是这样写的:A complete path through a use case, from the first step to the last, is called scenario. 大多数用例有一些不同的scenario,但是这些scenario一般共有一个目标(说到这里,我想到上一篇文章中提到的:一个用例要定义一个开始点和一个结束点)。
        Alternate Path也是用例中重要的部分,不经常发生的并不是不发生,比如在上面的例子中,如果声音识别器坏掉的情况下…而且Alternate Path使得用例更完整。
        现在用例已经修改完毕了,但是要注意,在编写代码之前,查看一下用例和原来的需求是否可以对应。任何时候改变用例都要回来查看需求的变化。下面来修改我们的需求列表。
                

        下面我们要开始完成代码的编写,首先,需要一个声音识别器类型:
    

    public class BarkRecognizer
    
{
        
private DogDoor _door;

        
public BarkRecognizer(DogDoor door)
        
{
            
this._door = door;
        }


        
public void recoginze(String StrBark)
        
{
            Console.WriteLine(
" BarkRecognizer heard a '" + StrBark + "'");
            _door.Open();
        }

    }

 

        然后我们在对测试代码进行修改:

        static void Main(string[] args)
        
{
            DogDoor door 
= new DogDoor();
            BarkRecognizer recognizer 
= new BarkRecognizer(door);
            Remote remote 
= new Remote(door);
            Console.WriteLine(
"The dog is barking, he wanna ");
            
//remote.pressButton();
            recognizer.recoginze("Woof");
            Console.WriteLine(
"The dog is outside and ");
            Thread.Sleep(
10000);
            
//remote.pressButton();
            Console.WriteLine("The dog is barking, he wanna inside");
            
//remote.pressButton();
            recognizer.recoginze("Woof");
            Console.WriteLine(
"The dog is inside");
            
//remote.pressButton();
            Console.Read();
        }

        测试结果如下:

                

        这次修改中发生了一个问题:Dog door 无法自动关闭了!在实际开发中,需求变化导致的修改往往会让我们的程序千疮百孔,对于这样一个小的程序都会出现这种问题,何况我们的项目呢?但是,这种情况不是不能避免,问题也许是由于原先的设计,也许在于后来的开发上,及时调整,避免问题到了后面,不可收拾。
        我原来把自动关闭的代码写在了Remote中,现在可以同样在BarkRecognizer中贴入同样的代码,但是这并不是一个好的主意。想想如果说今后对于自动关闭的方法有修改时,那么需要修改所有贴有这个代码的地方,如果客户又要加入一种开门的方式,就又要粘贴一下这段代码,显然这与面向对象原则是背道而驰的。相对较好的解决方式应该是修改DogDoor类型,因为自动关闭是DogDoor本身的行为。修改代码如下:

    public class Remote
    
{
        
private DogDoor _door;

        
public Remote(DogDoor door)
        
{
            
this._door = door;
        }


        
public void pressButton()
        
{
            
if (_door.IsOpen)
            
{
                _door.Close();
            }

            
else
            
{
                _door.Open();                
            }

        }

    }


    
public class DogDoor
    
{
        
private Boolean _isOpen;

        Timer time;
        TimerCallback callback;

        
public Boolean IsOpen
        
{
            
get return _isOpen; }
            
set { _isOpen = value; }
        }


        
public DogDoor()
        
{
            _isOpen 
= false;
        }


        
public void Open()
        
{
            _isOpen 
= true;
            Console.WriteLine(
"The dog door is opened.");
            callback 
= new TimerCallback(this.Close);
            time 
= new Timer(callback, this10000);
        }


        
public void Close()
        
{
            _isOpen 
= false;
            Console.WriteLine(
"The dog door is closed");
        }


        
public void Close(object source)
        
{
            
this.Close();
        }

    }


        现在正常了:


                

        通过修改,我们可以看出:有时候需求中的一个变化能反映出系统的一些问题,你甚至不知道有这些问题。(Sometimes a change in requirements reveals problems with your system that you didn’t even know were there.)
变化是经常的,系统也应该在你修改或者编写他的时候经常有所改善。(Change is constant, and your system should always improve every time you work on it.)
        故事讲还在继续,但现在我们可以总结一下这两章中学习到的东西,一些OOA&D的工具或者说思想:
        需求:
            1、 好的需求保证了你的系统工作如同你的客户所期望的
            2、 确定你的需求覆盖了系统用例中的所有步骤
            3、 使用你的用例并找出客户忘记告诉你的事情
            4、 你的用例往往会展现一些需求中不完善或者是丢失的东西,而这些东西你应该加入你的系统中
            5、 随着时间流逝,需求会变化或者膨胀
        面向对象原则:
            1、 封装变化


posted on 2007-09-04 17:20 KiddLee 阅读(2097) 评论(12)  编辑 收藏 网摘 所属分类: OOA&D学习与探索系列

评论

#1楼 2007-09-04 21:05 金色海洋(jyk)      

面向对象原则:
1、 封装变化

一直不理解这句话,变化怎么能够封装起来呢?
我的原则是:拥抱变化!

另外对这种说明问题的方式很是不习惯。可能是一直在面向过程,面向数据库吧。
    回复  引用  查看    

#2楼 2007-09-04 21:45 金色海洋(jyk)      

借贵宝地一用:
刚建了一个群:46212334 —— 烦恼回收站,开心大奉送。

估计大家或多或少都有点烦心的事情吧,或者程序上遇到点麻烦。
或者工作上不顺心。

建了一个群,就是闲聊,目的就是发泄心中的不愉快,换一个好心情!

当然聊点技术也是可以的:)
    回复  引用  查看    

#3楼[楼主] 2007-09-04 21:56 KiddLee      

@金色海洋(jyk)
封装变化是指将变化的部分封装到尽可能少的方法中,个人理解就是提高重用的体现。与你所说的拥抱变化并不矛盾
换句话说当变化来临前,把我们的设计做好,尽可能的减少变化的点,以减少因变化带来的工作量。然后我们再拥抱变化

的确,在3年的MIS开发中,我也有一段时间一直感觉自己是在面向过程。但当我现在回头再想想自己做过项目,实际上是把别人编写好的对象串接的过程,然这些对象变成一些客户可以使用的工具。

实际上,这些工作也并不能说是面向过程,比如说,自定义一个列表控件,在各个页面中使用。当客户对这个控件样式提出了一些要求,我们只要修改这个控件的代码就可以,而不用到各个页面中去修改,这就是重用,这就使封装变化。这样我们也就可以大胆的拥抱变化

还有就是设计模式的应用中,更多的能体现出这种封装变化的思想

对于《Head First Object-Oriented Design and Analysis》这本书,实际上是在表达一种思想。所以描述的地方相对较多一些

对于我的解释是否满意:)

谢谢你的关注
    回复  引用  查看    

#4楼 2007-09-05 06:21 金色海洋(jyk)      

我第一步要做的就是:尽量避免重复的代码!

功能类似的代码段只出现一次,这样就好修改了。
在我看来好多地方都属于重复的代码,比如表单。
如果一个表要有一段添加、修改的代码(或者叫做类),那么两个表就要有两个!
而对于我来说这两段添加、修改的代码就是重复出现了(冗余代码)。

我正在尽力去掉这种“冗余”——利用表单控件。目前50%的表单已经可以达到没有冗余(或者说不用写代码)的情况了,下面就是去掉复杂页面的“冗余”情况。

拥抱变化就是说,不管你怎么变,我的(代码)变化都要达到最少,甚至点几下鼠标就可以完成。


ps:不好意思,你说的我不是太理解,理解了一部分了吧。如果我的理解没有错误的话,难道我一直在按照你说的这种方式来写程序?而我还一直没有发现?



>>个人理解就是提高重用的体现
我的理解要想提高重用,最好的方法是写控件,比如分页控件等(当然控件本身也就是一个类)。比较常见的三层的方式,我是没有看到能重用些什么。或者重用率太低了?

    回复  引用  查看    

#5楼 2007-09-05 10:14 idzi[未注册用户]

继续关注……
    回复  引用    

#6楼[楼主] 2007-09-05 10:17 KiddLee      

@金色海洋(jyk)
哈哈,并不是你按照我说的方式来写程序,是面向对象的思想,实际上你我说得差不多了,我想这个问题就到这吧

对于三层开发,我也有一些想法,如果愿意的话可以加我的MSN,单独探讨一下,就不在这里赘述了
    回复  引用  查看    

#7楼 2007-09-05 11:02 游客一号[未注册用户]

lz估计什么时候可以把这个系列的文章写完?很是期待啊!!!
    回复  引用    

#8楼 2007-09-05 12:25 金色海洋(jyk)      

MSN的密码忘记了。
    回复  引用  查看    

#9楼[楼主] 2007-09-05 12:59 KiddLee      

@游客一号
大概要两个月吧,谢谢关注
    回复  引用  查看    

#10楼 2007-09-05 13:14 aspnetx      

期待下一篇
    回复  引用  查看    

#11楼 2007-09-05 19:00 金色海洋(jyk)      

其实我最转不过来弯的是

Console.WriteLine("The dog door is closed");

这类的语句,一句话门就关闭了。

但是在实际的编码中,类似于“关门”的事情时还要再写代码实现的。往往最终要转换成SQL语句——修改、添加数据库里的数据。

所以我就省略掉中间的若干步骤,直接处理(写)SQL语句。



    回复  引用  查看    

#12楼 2007-09-24 18:05 南守拥      

好不热闹,我也在占个位子!
    回复  引用  查看    



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 881725





相关文章:

相关链接: