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

推荐订阅源

V
V2EX
C
Check Point Blog
博客园_首页
B
Blog
D
Docker
U
Unit 42
量子位
I
InfoQ
有赞技术团队
有赞技术团队
Martin Fowler
Martin Fowler
GbyAI
GbyAI
L
LangChain Blog
云风的 BLOG
云风的 BLOG
博客园 - Franky
美团技术团队
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
月光博客
月光博客
Vercel News
Vercel News
Recent Announcements
Recent Announcements
雷峰网
雷峰网
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Google DeepMind News
Google DeepMind 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) 面向对象分析设计学习与探索(四):需求变化(Requirements Change) 面向对象分析设计学习与探索(三):收集需求(Gathering Requirement) 面向对象分析设计学习与探索(二):好的应用程序设计(Well-designed apps rock) 面向对象分析设计学习与探索(一):开篇 类型构造器 装箱拆箱续 Session Cookie and Persistent Cookie 第一次执行方法 我犯错了 装箱拆箱 接口函数还可以声明为private
面向对象分析设计学习与探索(五):分析(Analysis)
KiddLee · 2007-09-26 · via 博客园 - KiddLee

    在开发的过程中,我们所写的程序如同在真空中一样,相对理想的环境,相对较好的机器。然而一旦软件部署到客户端,软件就在现实世界中工作。此时,很多性能和并发的问题就产生了。

    让软件在真实的世界中正常工作的关键是分析:在发布你的程序前,指出潜在的问题,然后解决他们。分析帮助你确保你的系统在现实环境中工作。

    分析的第一步就是:指出潜在的问题:

    回到上一章的故事,还记得那个改进后的Dog Door。现在有了一个新的问题:邻居家的狗叫的时候,这个门也会自动打开。

OOAD4_1

   现在问题发现了,根据问题要重新修改用例。接收到声音信号后,BarkRecognizer要识别是否是这家人的小狗叫。修改后用例如下:(黑色粗体为修改的部分)

OOAD4_2

    从用例中我们可以看出,现在声音识别器在获得音频信号后,要进行比对,以确认这个声音是否为此家人的小狗。这样,我们就要保存一个小狗的声音用来比对。所以我们需要一个新的用例来保存狗的叫声。

    OOAD4_3

    用例更新后,程序需要做相应的修改,但是有一个问题出现:如何更改。实际上程序有很多实现方式。如何选择?

    有人认为:简单是最好的。既然需要一个对象存储小狗的叫声,当需要的时候进行比对,那我们可以用一个String对象来存储。只需要在Dog Door 对象中进行修改。代码修改如下:

public class DogDoor

    
private String _allowedBark; 

    
public String AllowedBark 
    

        
get return _allowedBark; } 
        
set { _allowedBark = value; } 
     }
 

     
// 
}
 

    相应的BarkRecognizer()中也需要修改:

    public class BarkRecognizer 
    

        DogDoor door 
= new DogDoor(); 

        
public void recognizer(String Bark)
        

              
if (door.AllowedBark == Bark) 
              

                 door.Open(); 
               }
 
         }
 

         
// 
      }
 


    也有人更忠实于面向对象。在这种情况下,编写一个Bark类型,并赋予相应的比较方法。

添加Bark类型:

public class Bark 

    
private String _sound; 

    
public Bark(String sound) 
    

        _sound 
= sound; 
    }
 

    
public String Sound 
    

        
get return _sound; } 
    }
 

    
public Boolean Equal(Bark bark) 
    

        Boolean flag 
= false
        
if (bark._sound == _sound) 
        

            flag 
= true
        }
 
        
return flag; 
    }
 
}
 


当然,Dog Door类型也需要修改,代码如下:

public class DogDoor 

    
private Bark _allowedBark; 
    
public Bark AllowedBark 
    

        
get return _allowedBark; } 
        
set { _allowedBark = value; } 
    }
 

    
// 
}
 


BarkRecognizer类型中的修改如下:

public class BarkRecognizer 

    DogDoor door 
= new DogDoor(); 
    
public void recognizer(Bark Bark) 
    

        
if (door.AllowedBark.Equal(Bark)) 
        

            door.Open(); 
        }
 
    }
 

    
// 
}
 


    那么哪一种方式更好呢?在这里要提到一个问题:解耦合。也就是说,你的对象对于其他的对象是独立的,或者说一个对象的变化不会导致其他对象的变化。书中写道:Delegation helps our applications stay loosely couples。意思是说:Delegation帮助我们的程序保持松耦合,对于Delegation的翻译,我一直觉得是代理。但在这里我感觉是封装的意思,不知我的理解是否正确。回到刚才两个方法的讨论:如果对于小狗的叫声存储的是声音文件,比如说WAV,对于第二种方式我们只需要修改Bark类型中的Equal方法就可以,BarkRecognizer类型中不需要修改。Delegation shields your object from implementation changes to other objects in your softwave

    但是现在又出现一个很实际的问题:小狗的叫声可能有很多种,无论哪一种,我们应该让门打开。那么在DogDoor类型中的AllowedBark应该是一组Bark对象,换句话说:AllowedBark应该是List<Bark>类型。

    说到这里,一个疑惑出现了,如何确定一个程序中的类型?注意用例中的名词。用例中的名词往往是你系统中所需要实现的类型。那么现在把用例中的名词圈出来。

OOAD4_5

    不难看出,很多名词是系统中需要的类型。当然也有些名词是不需要注意的,如;button owner outside inside

    书中提到一个词:textual analysis 文本分析。

    Looking at nouns and verbs in your use case to figure out classes and methods is called textual analysis.

    回到用例中,注意用例中的第三步:3.If it’s the owner’s dog barking. The bark recognizer sends a request to the door open. Owner’s dog是一个名字,但是我们不需要为dog创建一个类型,因为他是发起者,在系统之外。对于Bark,不要只把关注点放到Bark上,还要注意是the owner’s dog。

现在不难看出用例的重要性。尤其是对文本分析的重要性。OOAD4_6

    对于用例中的动词,实际上是系统重要实现的方法。

OOAD4_7

    完成分析后,明确了系统中需要的类型和方法,我们可以很简单的画出系统的类图。类图中可以描述类型之间的依赖关系。

OOAD4_8

    分析得差不多了,类图也画出来了。虽然类图可以很清楚的表现出类型之间的关系,但是不能告诉我们代码是如何实现的。下面我们来看看代码的实现:

    首先编写Bark类型

    public class Bark
    
{
        
private String _sound; 

        
public Bark(String sound)
        
{
            _sound 
= sound;
        }
 

        
public String Sound
        
{
            
get return _sound; }
        }
 

        
public Boolean Equal(Bark bark)
        
{
            Boolean flag 
= false

            
if (bark._sound == _sound)
            
{
                flag 
= true;
            }

            
return flag;
        }

    }
 

    
    在DogDoor类型中加入如下代码:

        private List<Bark> _allowedbarks; 

        
public List<Bark> AllowedBarks
        
{
            
get return _allowedbarks; }
            
set { _allowedbarks = value; }
        }
 


    修改BarkRecognizer中的recognize方法,代码如下:         

        public void recoginze(Bark bark)
        
{
            Console.WriteLine(
" BarkRecognizer heard a '" + bark.Sound + "'");
            
foreach (Bark allowbark in _door.AllowedBarks)
            
{
                
if (bark.Equal(allowbark))
                
{
                    _door.Open();
                    
break;
                }

                
else
                
{
                    
continue;
                }

            }

        }
 


    最后修改测试代码并查看结果:

        static void Main(string[] args)
        
{
            DogDoor door 
= new DogDoor();
            door.AllowedBarks.Add(
new Bark("Woof"));
            door.AllowedBarks.Add(
new Bark("Yip"));
            BarkRecognizer recognizer 
= new BarkRecognizer(door);
            Remote remote 
= new Remote(door);
            Console.WriteLine(
"The dog is barking, he wanna "); 

            Bark bark1 
= new Bark("Woof");
            recognizer.recoginze(bark1);
            Console.WriteLine(
"The dog is outside and ");
            Thread.Sleep(
10000); 

            Bark bark2 
= new Bark("Yip");
            Console.WriteLine(
"The dog is barking, he wanna inside");            
            recognizer.recoginze(bark2);
            Console.WriteLine(
"The dog is inside");
            Thread.Sleep(
10000); 

            Console.WriteLine(
"Another dog is barking");
            Bark bark3 
= new Bark("Hooh");
            recognizer.recoginze(bark3);
            Console.Read();
        }
 


    输出结果为:

OOAD4_9