惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
Help Net Security
Help Net Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
博客园_首页
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MongoDB | Blog
MongoDB | Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LINUX DO - 最新话题
PCI Perspectives
PCI Perspectives
博客园 - 三生石上(FineUI控件)
V2EX - 技术
V2EX - 技术
Spread Privacy
Spread Privacy
T
Tor Project blog
量子位
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
小众软件
小众软件
博客园 - 叶小钗
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
H
Help Net Security
Y
Y Combinator Blog
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tenable Blog
Scott Helme
Scott Helme
G
GRAHAM CLULEY
大猫的无限游戏
大猫的无限游戏
aimingoo的专栏
aimingoo的专栏
IT之家
IT之家
Schneier on Security
Schneier on Security
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
T
Threat Research - Cisco Blogs
博客园 - 司徒正美
Application and Cybersecurity Blog
Application and Cybersecurity Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Attack and Defense Labs
Attack and Defense Labs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
L
LangChain Blog
C
Check Point Blog
Google Online Security Blog
Google Online Security Blog
V
Visual Studio Blog
Latest news
Latest news

博客园 - KiddLee

数据库存储图像及使用Image控件显示 三层体系结构总结(六) Spring.Core IoC(一) Spring.Net 模块组成 Generating user instances in Sql Server is disabled. Use sp_configure 'user instances enabled' to generate user instances 面向对象分析设计学习与探索(六):好的设计=软件的灵活程度(good design=flexible software)继续 面向对象分析设计学习与探索(六):面向对象的灾难(OO Catastrophe) 面向对象分析设计学习与探索(六):好的设计=软件的灵活程度(good design=flexible software) 面向对象分析设计学习与探索(五):分析(Analysis) 面向对象分析设计学习与探索(四):需求变化(Requirements Change) 面向对象分析设计学习与探索(二):好的应用程序设计(Well-designed apps rock) 面向对象分析设计学习与探索(一):开篇 类型构造器 装箱拆箱续 Session Cookie and Persistent Cookie 第一次执行方法 我犯错了 装箱拆箱 接口函数还可以声明为private
面向对象分析设计学习与探索(三):收集需求(Gathering Requirement)
KiddLee · 2007-08-27 · via 博客园 - KiddLee

        相信每一个人都希望让客户满意。而且现在已经知道写一个好的软件的第一步就是确定软件所作的是客户想让它做的。但是你如何确定什么是客户想要的?如何确定客户知道他们真正想要什么?

        的确!在做项目项目的时候,我们常常被不确定的需求变化所困扰,当然如果说在开发时期要求需求一点不变化是不可能的,但是有些需求变化是致命的,会导致工作量成倍的上升,甚至是项目的失败。现在有个场景,我们看看如何做才能很好的挖掘用户的想法(这是编写成功软件的第一步)。

        情景:有一个用户要给自己的小狗修一个Dog Door,以至于他们不用再睡觉后听到狗叫,然后起床给它开门。当然,这个Dog Door 并不是简单的一个塑料片,他们希望通过一个遥控器按钮使这个Dog Door打开或者关上。

                

        从需求上看,好像很简单。我们只需要一个Dog Door和一个可以控制们的遥控器,让我们从Dog Door开始,首先要有一个DogDoor的类型,当然这个类型中有一些功能,如:开门、关门。

    public class DogDoor
    
{
        
private Boolean _isOpen;

        
public Boolean IsOpen
        
{
            
get return _isOpen; }
        }


        
public DogDoor()
        
{
            _isOpen 
= false;
        }


        
public void Open()
        
{
            _isOpen 
= true;
            Console.WriteLine(
"The dog door is opened.");
        }


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

    }


        然后在完成遥控器的代码:

    public class Remote
    
{
        
private DogDoor _door;

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


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

            
else
            
{
                _door.Open();
            }

        }

    }

最后我们来测试一下: 

    class Test
    
{
        
static void Main(string[] args)
        
{
            DogDoor door 
= new DogDoor();
            Remote remote 
= new Remote(door);
            Console.WriteLine(
"The dog is barking, he wanna ");
            remote.pressButton();
            Console.WriteLine(
"The dog is outside and ");
            remote.pressButton();
            Console.WriteLine(
"The dog is barking, he wanna inside");
            remote.pressButton();
            Console.WriteLine(
"The dog is inside");
            remote.pressButton();
            Console.Read();
        }

    }


                 好了,现在可以交给客户使用了。可是不久,客户就发现了问题。

                


 

客户忘记了用遥控器把门关上,结果很多小动物就进来了。看来这个们没有按照客户希望的工作。很显然,这个简单的软件并不符合客户的要求(当然这种意见他们原来并没有提出来)。现在我们回过头来重新审查我们对这个需求的理解,已确定我们的软件是客户想要的。现在一个问题产生了:什么是需求?
    是系统为了工作正常而必须做的工作细节


                        当需要收集需求时,我们最应该做的是:让客户说话。注意什么是系统需要做的,然后列出什么是系统将要做的。
        首先来听听他们说些什么

                

         根据他们所说的现在建立一个需求清单    1、 Dog door打开的时候至少12英寸高
    2、 按遥控器上的按钮,当门关上的时候,门打开;否则,门关上
    3、 一旦门打开了,在一定的时间后如果没有关闭的话,他将自动关闭

                

    这只是一个简单的需求清单,我们需要将他细化,以准确的指出当小狗要出去时都发生了什么!

            


        细化之后觉得这个清单中的第六步还是有些问题。在Fido(那只要出去的小狗)近来之前,门一直是开着的。这样的话,它近来之前就不必再叫了。现在我们在来修改一下。

                

书上教给我们一个不错的办法,对于有问题的步骤,或者是描述不足的部分使用小号修改,不必把后面删掉重新排号。


         现在这个清单已经很精确了,实际上,用了这就是根据需求清单写出的用例(use case)
        用例描述了你的系统为完成用户需求中的一个细节所需要做的事情。

                

        那么如何写好一个用例呢?
        通常一个用例由三部分组成:Clear Value,Start and Stop,External Initiator
        1、 Clear Value:很抱歉的是我不太明确应该怎么翻译,我觉得是一个明确的目标或者价值。每一个用例都要有一个Clear Value。如果说用例没能帮助客户达到他们的目标,那么用例就没有用了
        2、 Start and Stop:开始和结束。每一个用例都要定义一个起始点和一个结束点。一个进程开始后,在一个条件下,进程结束。在上面的用例中,Fido开始叫,这个进程就开始了。当Fido进门后,门自动关上,这个进程就结束了。
        3、 External Initialtor:我管它叫外部触发者。它必须是系统之外的人或物。在上面的用例中就是那个要出去的小狗。
                        我们有了需求清单和用例,现在我们要做的是回到需求,确定覆盖了系统必须做的所有事情。(将对应的需求填入用例,N/A是not applicable)

                

        这个方法不错,可以需求清单和用例很好的对应,在我们编写相应程序时不会因为不明确而漏掉什么。
        现在有了需求和用例,我们可以开始编码了。首先要修改Remote类型,使其在打开门一段时间之后自动把门关上,代码如下:

    public class Remote
    
{
        
private DogDoor _door;

        Timer time;
        TimerCallback callback;

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


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

            
else
            
{
                _door.Open();
                callback 
= new TimerCallback(_door.Close);
                time 
= new Timer(callback,_door,1000,0);
            }

        }

   }

        注意,这个地方的变化造成了一些修改,当然程序有很多种写法,这里就不再探讨这个问题了,造成修改的地方是:DogDoor类型中加入一个Close的重载方法:
     public void Close(object source)
     {
            Close();
     }

        最后我们需要修改原来的测试代码,去掉开门后按按钮的动作,让门自动关闭,在测试代码中用线程休眠来表示Fido已经出去,测试代码如下:

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


        测试结果还可以:

                        现在客户感觉满意了,我们也初战告捷了。