客户永远是对的:当需求改变时,你必须准备好更新你的应用程序并确保它运作的就像客户预期的那样。当客户有新需求时,要靠你来改变应用程序以符合新需求。
软件分析与设计的不变真理是:改变。无论你把应用程序设计的多好,应用程序总会是随着时间成长或改变。
需求时时在变,有时在项目中间,有时在你认为一切都已完成时。然而,假如有很好的用例,你通常能快速地改变你的软件以适应这些新需求。
从第一步到最后一步通过用例的完整路径成为场景。大部分的用例有一些不同的场景,但总是有相同的用户目标。
有时候,需求的变更揭露出关于系统你所不知道的问题。
变更是经常的,随着你的每次的实现,系统总是随之改善。
下面是对于狗门新的需求:
在这里,需求的变更是,需要一个辨认狗叫的传感器,当Fido叫的时候,有两条路径可以选择,
1.Todd或Gina听到狗叫,按下遥控器按钮
2.叫声识别器识别到狗叫,送出请求给狗门以打开狗门
二者任选其一。
完整代码参考,第二章给客户所需之物,这是在第二章的基础上对代码进行完善。
项目架构:
创建叫声识别器,BarkRecognizer.java:
1 package com.headfirst.dogdoor; 2 3 public class BarkRecognizer { 4 private DogDoor door; 5 6 public BarkRecognizer(DogDoor door){ 7 this.door = door; 8 } 9 10 public void recognize(String bark){ 11 System.out.println(" BarkRecognizer: Heard a ‘" + bark + "’"); 12 door.open(); 13 } 14 }
更新狗门模拟器,测试叫声识别装置,DogDoorSimulator.java:
1 package com.headfirst.dogdoor; 2 3 public class DogDoorSimulator { 4 public static void main(String[] args){ 5 DogDoor door = new DogDoor(); 6 BarkRecognizer recognizer = new BarkRecognizer(door); 7 Remote remote = new Remote(door); 8 9 //Simulate the hardware hearing a bark 10 System.out.println("Fido barks to go outside..."); 11 recognizer.recognize("Woof"); 12 13 System.out.println("\nFido has gone outside..."); 14 System.out.println("\nFido's all done..."); 15 16 try{ 17 Thread.currentThread().sleep(10000);//获取当前运行线程对象并让其休眠10s 18 }catch(InterruptedException e){} 19 System.out.println("...but he's stuck outside!"); 20 21 //Simulate the hardware hearing a bark again 22 System.out.println("\nFido starts barking..."); 23 recognizer.recognize("Woof"); 24 System.out.println("\nFido's back inside..."); 25 } 26 }
更新完成上述代码后,运行结果后,发现一个问题,就是狗门没有自动关闭,但是狗却被关在了门外。
原因是,我们没有将
1 final Timer timer = new Timer(); 2 timer.schedule(new TimerTask(){ 3 public void run(){ 4 door.close(); 5 timer.cancel(); 6 } 7 }, 5000);
上面的代码加入到程序中,导致叫声识别器没有自动关闭狗门。
好就按照要求,将代码加入叫声识别器中,现在先别忙着写代码,停下来思考一下,我们真的要把Remote.java中的相同的代码加入到叫声识别器中吗?
自动关门,遥控器要用到,叫声识别器也要用到,但是这样的话代码就会出现重复。
DogDoor的关闭为什么不让门自己关闭呢?我们只让Remote和BarkRecognizer两个调用就好,因为关门是门的事情,并且门自动关闭是在门打开之后,所以我们将自动关门代码添加到DogDoor的open()方法中,并移除之前在Remote中的自动关门代码。
1 public void open(){ 2 System.out.println("The dog door opens."); 3 open = true; 4 5 final Timer timer = new Timer(); 6 timer.schedule(new TimerTask(){ 7 public void run(){ 8 close(); 9 timer.cancel(); 10 } 11 }, 5000); 12 }
这是什么设计原则呢?
DogDoor的开关的动作是自己的事情,Remote和BarkRecognizer只是发送一个信号通知门要做什么事情。所以开关门不是Remote和BarkRecognizer要做的事情。
我们不能混淆各个事物自己的功能。