暑假回来之后,一直都在看关于面向对象建模的问题,断断续续的,今天终于是把这本书给读完了,感觉得记下些东西比较好。
如果说现在直接让我回忆这本书的内容的话,我可能什么也记不起来。所以只是是边翻目录边回忆了。
在这里,我想主要记下些些关于建模的基本过程吧
首先书里提出了一个疑问:良好的应用程序的基石。
良好的应用程序的基石是什么呢?
我们首先来回答一下什么是伟大软件。
伟大软件需要完成以下三个事情,一是确认你的软件做客户要它做的事。二是运用基本的OO原则来增加的灵活性。三是努力实现可维护,可重用的设计。
可以把完成这三件事当成是实现良好的应用程序的必须完成的三件事情。那么,接下来,我们就可以根据要完成的这三件事情进行详细的展开了。
在进入实现良好的应用程序的设计之前,我们先了解了以下的几个方面的知识。
第一,收集需求。
给客户之所需,我们已经知道编写伟大的软件的第一个步骤就是确保它完成客户要它做的事。但是如何理解客户真正的需求,确认用户知道他们想要的是什么。这就是良好需求的着力点。其实,简单地说,首先就是一个收集需求的阶段。
收集需求,我们要倾听客户,谈到需求里,最好让客户自己说。在我们知道了客户要什么了之后,创建一个需求列表。
我们要为这个系统的运行中出现错误做一个规划,这里就引出一个关于替换路径的问题。这创建需求列表的过程中,我们其实也正是在设计用例。
用例需要完成三件事情:一是要有清楚的价值,用助于实现客户的目标。二是第个用例都必须有明确的起点。某事件开始此流程,然后要有条件指明此流程已经完成。三是要用外部启动者。
在我们设计了一组组的用例之后,我们可以反过来使用用例来检查需求,看看需求是否已经覆盖了所有的功能。
检查完需求后就要吧开始准备编写一写程序代码了,然后我们可以写个一模拟器,模拟测试一些工作。我们不间要测试主要路径,同时也要测试替换路径。为了测试替换路径,我们也许会需要重新设计一些新的测试驱动。
第二,需求发生改变
接下来又说到了关于需求发生变更的时候,要学会使用替换路径替换掉原来路径中不适应需求的部分,但主要路径应该是你大部分时间想要遵循的路径。通过不同的用例会产生不同的场景。从第一步到最后一步通过用例的完整路径称为场景。大部分的用例有一些不同的场景,但总是有相同的用户目标。当我们在任何时候改变了用例,就必须回头检查你的需求,看看需求里是否需要加些什么。完成了需求列表之后, 我们可以再次编写代码。在我们编写的代码中出现重复程序代码是个坏主意,我们要尽量的避免,紧后就是重新设计测试驱动,运行模拟器。
第三,分析,什么是分析? 就是把自己的软件放到真实的世界中,想出潜在的问题,找出规划解决方案,修正出错的步骤,持续地更新用例。
在这个过程中,我们会用到几个知识,先是委托,委托有助于让应用程序保持低耦合,也即一个对象的改变不会引起一连串其他对象的改变。查看用例里的名词与动词,以整理出类与方法的动作叫做文本分析。这里面还涉及到一些关于类图的表示,类图是取得系统概况的好方法,可以向同事和其他程序设计师展示系统的各个部分。
第四,良好的设计与灵活的软件
首先的抽象基类的应用,在抽象出基类来了之后,也要记得去改变原来的UML类图。
当我们发现原来的设计存在问题,又一时不是很明显时,则可以在增加一些负荷,让问题完全给显露出来,然后再根据显露出来的迹象去改变原来的设计。
接口,子类从接口继承共同的行为,对接口编码而不是对实现,让我们的软件更加容易被扩展,能过对接口编码,我们的程序代码将使用该接口的所有子类,甚至是还没被创建的那些。
封装,可以避免程序代码的重复,还可以帮助我们捉住类免于不必要的改变。当认为应用程序中有某种行为很可能改变时,我们就经常会想要把它从应用程序里不改变的部分移开。我们应该将变化之物封闭起来。
变更,确保一个类只有一个改变的理由。也就是减少引起该类的变动因素,如果一个类试图做很多事情,那么就应该考试是否可以将其功能分解成多个类。
当我们有一组特性跨对象变化时,使用集合,像MAP来动态存储那些特性,我们将从类中移除许多方法,并且在新特性被加入应用程序时避免改变原来的程序代码。
第五,处理大问题
处理大问题的最佳方式是化整为零,我们已经知道取得良好需求的最佳方式是去了解系统应该做什么,我们知道通过封闭变化之物,我们的软件更有灵活性,更容易改变。我们知道对接口编码,而不是对实现编码,让我们的软件容易扩展。我们知道伟大的软件容易改变及扩展,并且做客户要它做的事。我们还知道分析帮我们确保系统能够动作在真实世界的情境中。
接下来,我们利用这些知识,从头到尾走一遍。
从需求和用例开始。
我们不知道用例,所以跟客户对话,然后对收集到的信息进行整理,知道这个程序的功能。功能是系统需要做的事情的一种高级的描述,我们从客户处取得功能,接着整理出实现这些功能所需要的需求。于是我们得到了功能列表。
在这个阶段,我们尽量把细节往后拖延,我们正在做大事,不能让小事卡住。
有了功能列表之后, 我们需要一用例图来告诉我们这个系统的总体轮廓。 我们可以使用功能列表来确认用例图是完整的,取把所有的功能项放到处理该功能的用例上。如果某个功能项不能与用例图对应,则得考虑这功能需要担心,它如何与系统相关,涉及到哪些参与者,是不是我们遗漏了什么。
接着,我们要做领域分析,检查我们的设计,并且是以客户所用的语言。我们以一种客户能真正理解的方式把为游戏系统所想到时的一切组合起来,这个流程称为领域分析。
完成了大问题的大分解,我们再检查一下之前设计好的功能与图形,整理出我们想要的模块来处理所有的这些功能,双及如何分开这些功能与需求。确认我们的涵盖了此游戏框架需要做的每一件事。
关于MVC设计模式
MVC是将应用程序的三人分成不同软件模块或程序单元的设计模式。这种划分的止的是为了让各组件能独立演进,解除不同角色的软件对象之间的耦合,并确保一个模块的改变不至于不慎影响到其他模块。Model表示应用程序的数据或状态,例如数据库信息;View是用户看到的视图,如网页或用户界面UI。Controller则是应用程序与用户交互作出响应的部分,例如处理键盘事件并决定展示哪个视图。
至此,我们走过和流程为:聆听客户,确认我们理解系统,为我们构建的系统画出蓝图,将大问题分解成较小的功能片段,运用设计模式帮我们解决较小的问题。
接下来,我们要逐步地把它转化成坦然有育的应用程序。但从哪里开始呢?从最重要的地方开始。
又什么是最重要的呢?应用程序中真正重要的鸮是架构上重要的事情,应该把焦点置于其上。
要确认某件事是否重要,只需要回答下面三个问题:
一,它是系统的本质吗?二,这是什么意思?三,我"到底"应该如何做?
之所以要找出重要的事情来,是因为它们都给项目带来了风险.我们想要从哪里开始没有关系,只要能减少后续的风险.
场景用助于减少风险,因为忘记需求就总是一个很大人风险.我们要保持正确的焦点,一次把焦点放在一个功能上,减少项目的风险,不要为无助于减少风险的功能分心.
接下来的工作,我们应该尽可能在现胡的基础上构建.还是要记住,我们只聚焦于会减少风险的事.架构的要点是减少风险以及建立次序.
当我不是很清楚一个功能的时候,应该问客户,然后就做些共同性分析,最后实现计划.
接下来是几个设计原则.
一,开放封闭原则 OCP. 禁止为修改而关闭,允许为扩展而开放.继承是OCP开闭原则的简单例子,合成也可以.
二,不自我重复原则 DRY.将共同之物取出来,并放于单一地方,重复的程序代码.DRY 关系到一个地方的需求,确保我们对应用程序中的每一个功能与需求只需要实现一次.DRY关系到时让系统中的每一个信息与行为的片段都保存在单一合理的地方.
三,单一职责原则 SRP.系统里的第一个对象应该具有单一职责,所有对象的服务都应该聚焦在实现该职责上.
四,Liskov替换原则 LSP. 子类型必须能够替换基础类型.违反了LSP就不能用继承了,这时要吧把功用性委托给其它类:如果你需要使用另一个类的功能性,但不想改变该功能性,考虑以委托代替继承.同时,使用组合可以将来自其它多个类的行为集合起来.组合中的行业不存在于组合本身以外,所以是一种强关系.聚合:被组合的对象需要存在于主要对象之外时使用.
接下来,我们可以开始进行迭代与测试了.
伟大软件的编写是迭代进行的,先针对整体轮廓操作,扫着迭代应用程序的每个片段,直到完成.
迭代有两种选择:
功能驱动开发,挑出应用程序的特定功能,并且规划分析及开发该功能,直到完成.
用例驱动开发.挑出通过用例的场景,并且编写程序代码以支持通过该用例的完整场景.
第一种的使用场合是:
功能示密切相关,你能更快地向客户展示可动作的程序,你不会落下功能.对具有许多示连接功能性片段的系统,进行得特别好.
第二种的使用场合是:
应用程序有许多流程与场景,而不是个别功能性片段,进行得比较好.
让你在每个开发阶段可以向客户展示较大的功能性片段.
是非常以用户为中心的,对交易式系统进行得特别好.
无论先了哪一种,都要进行下面几个部分:
一,功能分析.利用类图,更新类图,强调共同性,封闭性
二,编写测试场景,也就是测试案例.这也是测试驱动开发的一部分.
良好的软件是通过迭代造就而成.分析,设计,再一次迭代,一次一次完成应用程序更小更小的部分. 每当迭代时,重新的评估你的设计决策,假如它对你的设计全理,就别害怕改变.
三.比对我们的测试与设计,确认在我们设计的类中有方法可以让我们完成所有测试中的每一件事.
四,开始写代码.
关于测试案例的严格要求:
每个测试案例应该有ID与名称.
每个测试案例应该有一件特定的事要测试
每个测试案例应该用你提供的输入
每个测试案例应该有你预期的输出
大部分的测试案例具有起始状态
关于两种编程方式:
契约式编程,你正在与客户的程序代码合作,以对你将如何处理有问题的送交达成协议.
防御性编程,你下在确保客户获得"案例的"响应,不管客户要什么.
关于面向对象分析设计项目的生命周期:
一.列出功能列表:从高层次找出应用程序应该做什么
二.用例图:确认应用程序要执行的大流程,以及任何牵涉到的外部力量
(我想这前面两点应该算是一个概要的需要分析了)
三,分解问题,将应用程序分解成功能性模块,接着上决定上以什么样的次序处理每个模块.
四.需求.为每个功能模块想出各自的需求,并且确定它们符合整体的轮廓.
五.领域分析.想出你的用例如何对应到应用程序里的对象,确认你的客户跟你有相同的认知.
这前面五点都处理开发伟大软件中的第一个阶段:确认你的软件做客户要它做的事
六.初步设计:加入关于对象的细节,定义对象之间的关系,并且运用原则与设计模式.
七.实现:编写程序代码,进行测试,确认它有效动作.为每个行为,每项功能,每个用例,每个问题做这些事,直到你完成.
这两点处于开发伟大软件中的第二个阶段:运用基本的OO原则来增加灵活性.
四到七这里是一个迭代开发的过程.
八.交付,完成了.
从第七到第八,都要努力实现可维护,可重用的设计.