编程范式(六)--- 使用面向对象设计程序

111 阅读5分钟

面向对象分析、设计与编程

面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程(OOP),是面向对象开发的三个主要环节。简单点讲,面向对象分析就是要搞清楚做什么,面向对象设计就是要搞清楚怎么做,面向对象编程就是将分析和设计的的结果翻译成代码的过程。

面向对象分析

面向对象分析主要的分析对象是“需求”,因此,面向对象分析可以粗略地看成“需求分析”。实际上,不管是需求分析还是面向对象分析,首先要做的都是将笼统的需求细化到足够清晰、可执行。需要通过沟通、挖掘、分析、假设、梳理,搞清楚具体的需求有哪些,哪些是现在要做的,哪些是未来可能要做的,哪些是不用考虑做的。

从最粗糙、最模糊的需求开始,通过“提出问题-解决问题”的方式,循序渐进地进行优化,最后得到一个足够清晰、可落地的需求描述。

需求分析的过程实际上是一个不断迭代优化的过程。不要试图一下就给出一个完美的解决方案,而是先给出一个粗糙的、基础的方案,有一个迭代的基础,然后再慢慢优化。这样一个思考过程能摆脱无从下手的窘境。

面向对象设计和实现

面向对象设计和实现要做的事情就是把合适的代码放到合适的类中。至于到底选择哪种划分方法,判定的标准是让代码尽量地满足“松耦合、高内聚”、单一职责、对扩展开放对修改关闭等各种设计原则和思想,尽量地做到代码可复用、易读、易扩展、易维护。

面向对象分析的产出是详细的需求描述。面向对象设计的产出是类。在面向对象设计这一环节中,将需求描述转化为具体的类的设计。这个环节的工作可以拆分为四个部分。

  • 划分职责进而识别出有哪些类

    根据需求描述,我们把其中涉及的功能点,一个一个罗列出来,然后再去看哪些功能点职责相近,操作同样的属性,可否归为同一个类。

  • 定义类及其属性和方法

    识别出需求描述中的动词,作为候选的方法,再进一步过滤筛选出真正的方法,把功能点中涉及的名词,作为候选属性,然后同样再进行过滤筛选。

  • 定义类与类之间的交互关系

    UML统一建模语言中定义了六种类之间的关系。它们分别是:泛化、实现、关联、聚合、组合、依赖。从更加贴近编程的角度,对类与类之间的关系做了调整,保留了四个关系:泛化、实现、组合、依赖。

  • 将类组装起来并提供执行入口

    要将所有的类组装在一起,提供一个执行入口。这个入口可能是一个main()函数,也可能是一组给外部用的API接口。通过这个入口,能触发整个代码跑起来。

对于简单的需求设计,识别出来的类也并不多。但如果面对的是更加大型的软件开发、更加复杂的需求开发,涉及的功能点可能会很多,对应的类也会比较多,一开始就根据需求逐句罗列功能点的方法,最后会得到一个长长的列表,就会有点凌乱、没有规律。针对这种复杂的需求开发,首先要做的是进行模块划分,将需求先简单划分成几个小的、独立的功能模块,然后再在模块内部,进行面向对象设计。而模块的划分和识别,跟类的划分和识别,是类似的套路。

辩证思考与灵活应用

在上述的讲解中,面向对象分析、设计、实现,每个环节的界限划分都比较清楚。而且,设计和实现基本上是按照功能点的描述,逐句照着翻译过来的。这样做的好处是先做什么、后做什么,非常清晰、明确,有章可循,即便是没有太多设计经验的初级工程师,都可以按部就班地参照着这个流程来做分析、设计和实现。

不过,在平时的工作中,大部分程序员往往都是在脑子里或者草纸上完成面向对象分析和设计,然后就开始写代码了,边写边思考边重构,并不会严格地按照刚刚的流程来执行。而且,说实话,即便在写代码之前,花很多时间做分析和设计,绘制出完美的类图、UML图,也不可能把每个细节、交互都想得很清楚。在落实到代码的时候,还是要反复迭代、重构、打破重写。

毕竟,整个软件开发本来就是一个迭代、修修补补、遇到问题解决问题的过程,是一个不断重构的过程。没法严格地按照顺序执行各个步骤。要灵活将理论应用到实践才行。