面向对象分析与设计
学习面向对象分析和设计,即使您以前在类中尝试过并发现它很复杂,也可以使用一种简单的方法。
引言
这是什么东西?它有什么好处吗?如果我这样做,我的老板会认为我在浪费时间,或者是在找借口不工作。在您迫切需要为下一个软件进行properly设计时,是否曾有过这些想法?
也有可能您以前尝试过设计软件,但发现它只是耗时且没有益处。但在您的职业生涯中,您会反复出现这样的想法:我应该学习什么是设计模式,我应该如何掌握MVC,以及有一天我会设计出可重用、模块化且易于阅读的东西。
在这篇文章中,我将介绍如何properly设计您的下一个软件的基础知识,即使您上次失败了。
您将学到什么?
- 您上次的设计尝试为什么会失败?
- 当您想进行设计时,如何与您的经理/老板沟通?
- 您将如何成功地进行设计?
- 什么是软件开发过程?
- 什么是面向对象分析?
- 什么是面向对象设计?
- 什么是设计模式?
- 以及任何让您感到困惑的中间内容
您将学不到什么?
- 您将学不到Java、C#或C++的语法
- 您将学不到函数和变量的区别
- 您不会被大量的设计模式列表压垮
- 您在这里学不到面向对象编程
什么?(您在读完最后一行后可能会说)没有面向对象编程,那我为什么在这里浪费时间。这篇文章是关于面向对象设计的,但不是编程。我们都知道面向对象编程,即如何在C#中编写一个类并创建一个对象,或者扩展一个类,并且您知道通过经验,这并没有什么帮助。
正如一句名言所说:“知道如何使用锤子并不能让你成为一名建筑师。”是真的吗?同样,学习Java编程也不会让你成为一名优秀的软件工程师(或软件程序员、开发者、软件架构师)。
背景
在我本科项目的早期,我曾认为设计就是写算法,因为我没有学过面向对象编程。后来,当我学到面向对象编程时,我曾以为只要学完Dietel and Dietel这本书中的1000页内容,就可以征服世界了。
但事实并非如此。我常常抓耳挠腮也写不出程序。我还注意到,如果我6个月后再次打开程序,它就像一个谜一样,连福尔摩斯都解不开。
然后,在大四时,我学了面向对象分析与设计这门课。但不幸的是,重点是UML建模。我曾认为UML很酷——你只需生成一些图表交给开发人员,他们就会根据你的设计编写代码(这会让你很自豪)。
当时我们使用的UML建模工具甚至还有一个选项,可以根据你的UML类图自动生成代码。多棒啊,现在我用UML模型设计,然后生成代码,编译代码,然后卖给客户,像比尔·盖茨一样致富。太棒了。
之后,现实来了,我从未能够生成像样的、模块化、易于扩展和易于理解的设计(从这些工具生成的代码从未编译成功,因为UML工具只生成存根)。然后一段混乱的时期就开始了。
后来在我的本科学习中,我学习了与软件工程、软件架构、软件过程模型和软件项目管理相关的课程。但直到很久以后,我才能够将所有东西融会贯通。
我仍然看到人们在这些概念上挣扎,无法将它们融会贯通。他们被大量无序的信息淹没。理解所有这些信息的一个关键是参与到一个项目中。该项目的唯一产出应该是用户可以使用的软件。
在这篇文章中,我将分享一些基本的面向对象分析与设计原则、实践以及我的经验,您可以在下一个项目中使用它们。
软件开发过程模型简介
我们都使用某种过程或步骤来开发软件。我使用的最简单的过程模型是,我在纸的背面写下6行字,称之为功能列表,然后打开Visual Studio开始编写代码。就是这样。一个我上大学时使用的过程模型。
我大二时用Visual Basic 6.0编写了我的第一个商业软件(只有一个用户使用,后来他放弃了),也是使用了这个过程模型。
我学习并应用了许多软件开发过程模型到许多项目中。
有一个过程模型(被许多权威人士批评)是瀑布模型。瀑布模型步骤如下:需求收集、分析、设计、实现和测试。
瀑布模型的问题在于,您按照上述确切的顺序完成所有工作。首先,**所有需求**都从客户那里收集。一个团队分析需求,编写文档,并为设计团队准备规格说明。然后设计团队根据规格说明开发设计,并将设计交给实现团队。实现团队根据设计编写代码。最后,测试团队根据规格说明测试软件。
一切都是按顺序进行的,在最终产品交付给客户之前会花费大量时间(数月甚至数年)。统计数据显示,当使用瀑布模型交付产品时,大量的客户拒绝接受该产品,因为它不符合他们的需求。
您可能听说过“顾客永远是对的”这句行话。这在软件开发中是绝对适用的,因为如果客户不喜欢最终产品,那么所有的努力(数月甚至数年)都将白费。
为了解决这个问题,还有另一种哲学叫做迭代和演进式开发。基于这种哲学,有许多软件开发过程模型。一些例子包括Scrum、极限编程(XP)和Rational Unified Process。它们也被称为敏捷开发过程。
迭代开发的概念很简单。软件开发被组织成一系列小的项目,称为迭代。每次迭代都有其分析、设计、实现和测试。在每次迭代结束时,会征求客户的意见。如果客户不同意,那么损失就很小(通常是几周),与瀑布模型相比。
现在您已经理解了迭代和顺序过程模型之间的基本区别。许多组织现在使用迭代开发过程模型。关键在于最小化浪费(数月 vs 数周)。
为什么我需要理解过程模型
很长一段时间以来,我一直认为设计软件是这样的:我一开始就设计好所有东西,然后利用这个设计开始编码、编译,然后将运行的软件交给最终用户。
事实证明,这并不是最好的方法。您将不得不更改您的设计,并且您的设计会随着时间而演进。完美的設計是一種神話。在后续的迭代之后,您可能会意识到您最初的设计很糟糕。
另一点是,您不应该一开始就为所有需求进行设计。您应该为当前迭代制定详细的设计。
因此,关键要点是您应该使用迭代开发过程,并且项目开始时不必完成所有设计。同样,您所设计的任何东西都不是完美的,在项目的生命周期中都会被更改或演进。
面向对象分析与设计——最需要的定义
当我用VB 6.0开发我的第一个项目时,我对自己感到失望。这是因为代码中一小部分的任何更改都会传播到软件的其他所有部分。
原因是,我不知道如何编写模块化代码。虽然在过程式语言(VB 6.0是过程式的)中编写模块化代码是可能的,但在VB 6.0中却很困难且不受原生支持。
开发一个只有4个功能的简单软件简直是噩梦。进行任何代码更改都令人恐惧,因为我不知道面向对象编程。
解决这个问题的方法是面向对象编程。它使我能够编写模块化程序。在解释OOP和OOAD如何帮助我之前,让我们先讨论过程与开发方法论的区别。
开发过程与开发方法论的区别
开发方法论是过程内部的东西。开发方法论的例子包括结构化编程、面向对象编程和服务导向编程。
开发过程定义了一系列用于执行软件开发活动的步骤。软件开发过程的例子包括瀑布模型、Rational Unified Process、Scrum和极限编程。通常,您可以选择任何过程模型,然后在该过程内采用任何开发方法论。
面向对象分析
面向对象方法论有一个重要好处,但没人告诉您:您能够使用现实世界的术语或领域特定术语进行设计。例如,如果您正在处理与银行服务相关的软件,那么您可以在软件代码中使用诸如“账户”、“账本”、“资产负债表”之类的术语(作为类名或属性)。
这有什么好处?您可以像现实世界中的系统一样设计软件。这使得您更容易更新、修改和与客户沟通。因此,面向对象分析就是识别可以将现实世界对象表示到软件世界中的机会。
面向对象分析的第一步是倾听客户的故事并将其记录下来。故事是用客户自己的话描述客户的痛苦和收益。您的工作是解决这些客户痛苦和/或帮助客户实现积极收益。
可能不止一个客户故事。您可以在一次迭代中处理一个或两个用户故事。但单次迭代不要处理超过10%的故事。下一步是从用户故事设计领域模型。
要设计领域模型,我一直使用的一个简单技巧是阅读用户故事并划出名词。这些名词是您领域模型中潜在类的候选者。领域模型只是描述类的名称和/或类的属性。领域模型不描述任何实现细节,例如类中的函数。
总而言之,有两个步骤
- 写下用户故事
- 设计领域模型
接下来的例子将展示这一点。
面向对象设计
看到一个对象并说“嗯,它是一堆变量”是相当容易的。让我分享一个个人故事:我曾重构了一段代码,并设计了一个由两个基本类型组成的独立类。有趣的是,另一位开发者为我创建了一个新变量而欢呼。
周围有许多开发者都有这种想法。这就是创建类就是创建新变量。这并不是人们使用面向对象方法论的原因。如果您只是想要一组变量名,那么您可以在C语言中使用`struct`(C语言不是面向对象编程语言)。
面向对象设计是关于您的对象如何相互协作。在这里,您将决定谁将创建哪些对象,以及它们将如何交互以满足用户故事的需求。
分析中最重要的部分是识别用户故事中的领域类,而面向对象设计中最重要的部分是识别对象之间的协作以满足用户故事。
除了设计协作之外,还有软件社区遵循的原则和模式。四人帮设计模式(Gang of four patterns)在软件设计中被广泛使用,但这些模式值得另一篇文章(我很快会与您分享,以及我学习设计模式的个人经历)。
如果您是设计新手,请不要被所有这些模式的东西吓倒。一开始,只需专注于一两个原则。然后扩展您的学习,掌握更多的原则和设计模式。
您应该从哪些最重要的原则开始?
不要被原则和设计模式吓倒。我的建议是,一开始先专注于您感到舒适的一两个原则和设计模式,然后在此基础上发展。
我发现一个非常有用的重要原则,我建议您使用它:
“组合优先于继承”。
也就是说,尽量避免使用继承。在任何您认为继承是答案的情况下,都使用组合。
此外,如果您从未在代码中使用过接口,那么从今天开始使用接口。这将使您能够编写可重用和模块化的软件。
应用这两个原则,在接下来的几周内,您将体会到面向对象分析与设计的力量。
面向对象分析与设计的优点
通过这些原则和面向对象编程的知识,我能够编写出模块化且易于阅读的软件。此外,如果我现在打开10年前写的代码,我仍然可以轻松理解并轻松更新代码。
简单示例
下面是一个简单的例子,展示了一个简单的面向对象分析与设计过程。
首先,我将分享一个我们将在本例中处理的用户故事
用户故事
- 顾客带着要购买的商品来到收银台
- 收银员在柜台打招呼并开始新的销售
- 店主输入所有商品
- 系统计算订单总金额和税金
- 顾客付款
- 系统打印收据并更新库存
面向对象分析步骤
按以下顺序有三个步骤
- 识别类名
- 识别属性
- 识别关联
现在我建议您在用户故事文本中划出所有您认为可以作为代码中类名的名词。
通过阅读上面的用户故事,以下是我能想到的所有类名
领域模型
您可以在图表中看到,它不是使用任何UML工具开发的。只是用一支笔和一张草稿纸。我超过60%的设计都是用纸或白板完成的。
下一步:识别属性和关联。属性是定义类或对象的。属性可以是ID、金额或任何可测量的事物。关联定义了类和对象之间的关系,说明一个类如何与另一个类连接。
下图显示了上面展示的类图的属性和关联
带有属性和关联的领域模型
面向对象设计步骤
分析之后,我们进入面向对象设计,以下是步骤
- 为每个场景绘制序列图
- 绘制设计类图
- 应用设计原则和软件设计模式
序列图用于显示类对象之间的消息传递。它是面向对象设计中最重要的工具,因为它有助于设计软件中涉及的对象行为。
这是我绘制的用于处理用户故事的序列图
序列图
此序列图显示了对象之间用于完成用户故事目标的消息及其发送顺序。
从序列图,我们可以轻松地得到设计类图。设计类图是我通常在深入编写代码之前创建的最后一个工件。
从序列图绘制设计类图非常容易。只需在箭头指向的类中写下方法名即可。例如,`GetItem()`消息从`Sale`类发送到`Item`类。因此,`item`类将包含`GetItem()`方法。
设计类图
在设计类图之后,我们可以应用面向对象设计原则和设计模式,但我将另发一篇帖子来介绍设计模式和原则的应用。
从这里,我们可以开始编码。
这是一个非常简单的例子来展示这个过程。对于真实的、现实世界的面向对象分析与设计示例,您可以查看此链接。
到目前为止的总结
到目前为止,您已经了解了什么是软件开发过程、软件开发方法论以及它们之间的区别。为什么面向对象分析与设计比面向对象编程更重要。您了解了面向对象分析和面向对象设计的步骤、技术和目的。
您还通过一个简单的例子学习了如何使用基本但最重要的原则和技术来正确地设计软件。
您上次的设计尝试为什么会失败?
许多开发人员曾尝试properly设计软件项目,但都失败了或未能继续。因此,我整理了一份关于面向对象分析与设计的误解以及如何解决它们的清单。
如果您只是学会了完美设计
项目开始时的完美设计是一种神话。您的设计将随着时间的推移而演进、更改、纠正和修改。许多人认为他们必须在开始时就完美地设计,然后将该设计文档视为神圣的经文。事实是,没有人能在开始时就提出完美的设计。
软件设计是一个启发式过程。它是您在项目生命周期中不断更新的东西。没有公式可以每次都用于产生最佳的面向对象设计。它涉及到痛苦的尝试和错误,从中您可以学习,然后将这些经验应用于未来的项目。
您必须在编码之前完成所有分析和设计
许多开发人员和学生认为,在开始编码之前应该完成所有需求的分析和所有设计,并且在构建过程中,不能对其进行更改或扩展。
这是不正确的。如果在编码过程中,团队或开发人员发现设计可以扩展或缩减,那么就应该这样做。
同样,在迭代开发中工作时,通常一次迭代只处理10%的总需求。因此,您只需要为10%的总需求或用户故事进行设计。如果您有10个用户故事,那么在第一个迭代中处理一个最重要的故事(由客户指示),并仅为此进行设计。
您必须为设计提供足够的时间
当我开始认真对面向对象设计感兴趣时,我花了数周时间进行设计,并思考如何提出一个完美而完整的方案。但编码时,事情并没有按预期进行,我感到很失望。
经验法则是,对于为期三周的迭代,您不应花费超过一天的时间。在开始编码之前,我只花费2到4个小时。这并不意味着您在构建过程中不能回到设计阶段几个小时。您也可以在构建过程中与队友会面并讨论设计决策。
您认为UML(统一建模语言)是万能的
如果有人告诉您UML建模是万能的,并推荐一些昂贵的CASE(计算机辅助软件工程)工具,那么您应该来看看我的笔记本。我的大多数设计都没有用到我们公司拥有的CASE工具。在团队设计时,我们使用白板,然后拍下照片,并将这些照片发布到项目目录中。
我认为设计不是用漂亮的彩色盒子画出来的,并将其整齐地排列起来。纸上的粗略图纸与使用CASE工具绘制的图纸一样有效。OOAD是为了获得一个全局视图,并在编写代码时与您的同事以及您自己进行沟通。
UML只是一个用于翻译您的设计理念并可以与其他开发人员共享的工具。仅仅学习UML并不能让你成为一个好的设计师。
您必须应用所有的模式和原则
如果您了解所有面向对象的设计原则和模式,那么您可能会意识到您想在进入构建之前应用所有这些原则和模式。如果您这样做,那么您将不会成功。根据实际情况或问题,应用原则和模式,您将能够设计出好的软件。
我建议您制定一个您完全理解的模式和原则的优先级列表。然后,根据您面前的问题应用这些模式。
您不知道如何与您的老板/经理打交道
您的老板可能在您提出面向对象分析与设计的想法时表示反对。在您老板看来,这看起来像是一项额外的任务,不会为您的软件添加任何代码行。此外,您的老板可能不是编程背景出身,不会意识到OOAD的重要性。因此,有一些方法可以管理您的老板。
老板有两种
- 质量驱动型
- 进度驱动型
识别是什么影响您的老板或经理。如果您的老板是质量驱动型的,那么您可以向他展示面向对象分析与设计如何帮助他实现更好的质量特性,如模块化、可读性和可靠性。
如果您的老板是进度驱动型的,那么您可以做的第一件事就是向他表明分析和设计活动不会花费太多时间(在三周的迭代中只需2-8小时)。您还可以向他展示其他节省时间的好处,例如良好的设计可以节省项目后期的时间,例如当您需要更新或更改软件的某个功能时。
What Next?
在评论区写下您喜欢这篇文章的内容。另外,写下您想学习的内容,因为我打算很快再写几篇关于这个主题的文章?
此外,如果您想了解更多关于面向对象设计模式,请查看Code Project上的这些文章
历史
- 2016年10月31日:更新
- 为示例中涉及的所有类添加了UML图和源代码
- 删除了关键的拼写和语法错误