




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
敏捷软件开发 原则、模式与实践读书笔记3敏捷软件开发:原则、模式与实践读书笔记32010年04月01日星期四17:20第18章薪水支付案例研究:第一次迭代开始第18章薪水支付案例研究:第一次迭代开始-18.1介绍本章使用的用户素材都是很简单的,这是初期迭代的特征,仅提供用户所需商业价值中最小的部分。本章进行快速的分析和会话设计,这通常发生在一次迭代开始时。下一章进行实际的设计工作,完成但愿测试和实现。第18章薪水支付案例研究:第一次迭代开始-18.1.1规格说明描述在和客户交谈时关于第一次迭代中的素材的记录。根据用户素材,可以首先生成数据库模式(database schema),不过在使用这种方法产生的应用程序中,数据库成为了关注的中心。数据库是实现细节,应该尽可能推迟考虑数据库。有太多的应用程序,之所以和数据库绑定在一起而无法分开,就是因为一开始设计时就把数据库考虑在内。请记住,抽象的定义,本质部分的放大,无关紧要部分的祛除。在项目的当前阶段,数据库是无关紧要的;它只不过是用来存储和访问数据的技术而已。第18章薪水支付案例研究:第一次迭代开始-18.2基于用例的分析先来考虑一下系统行为,而不是系统的数据。一种捕获、分析系统行为的方法是创建用例(user case)。按照最初Jacobson的描述,用例和XP中的用户素材的概念非常相似。用例就是更详细一点的用户素材。一旦在迭代中要实现当前该用户素材,这种详细是合适的。在进行用例分析时,我们关注用户素材和验收测试,以找出系统的用户会执行的操作种类。接着我们会努力弄清楚系统怎样去响应这些操作。列举了7个本地迭代选取的用户素材。下面把用户素材转化为详细的用例。只要有助于考虑出每个素材的代码设计即可,不要陷入过多的细节。第18章薪水支付案例研究:第一次迭代开始-18.2.1增加雇员根据增加雇员用例分析操作方面:利用COMMAND模式,创建AddEmployeeTransaction基类,三个派生类AddHourlyEmployeeTransaction、AddSalariedEmployeeTransaction、AddCommissionedEmployeeTransaction。把每项工作划分到自己的类中,遵循SRP原则。也可以把所有代码放到一个模块中,这样就减少了类的数量,系统也更简单,但使所有的操作代码集中于一个模块造成庞大切可能出错的模块。对象模型:抵制住记录规划或字段结构等数据库倾向的诱惑,从对象模型的角度思考:图18.2:Employee基类,3个派生类HourlyEmployee、CommissionedEmployee、SalariedEmployee。第18章薪水支付案例研究:第一次迭代开始-18.2.2删除雇员描述删除雇员用例。第18章薪水支付案例研究:第一次迭代开始-18.2.3登记时间卡描述等级时间卡用例。用例表示,一些操作只能应用于某类雇员。这加强了不同类的雇员应该使用不同的类表的观点。第18章薪水支付案例研究:第一次迭代开始-18.2.4登记销售凭条用例4:登记销售凭条。与用例3类似,暗示一些操作只能应用于某类雇员。第18章薪水支付案例研究:第一次迭代开始-18.2.5登记协会服务费用例5:登记协会服务费协会会员有自己的成员标识。第18章薪水支付案例研究:第一次迭代开始-18.2.6更改雇员明细用例6:更改雇员明细该用例具有启迪性。由于可以把雇员从钟点工,修改为带薪雇员。显然图18.2并不合适。在薪水计算中,使用STRATEGY模式也许更恰当。图18.6:Employee类持有一个名为PaymentClassification的对象,这个对象具有HourlyClassification、SalariedClassification、CommissionedClassification。HourlyClassification含有Timecard对象列表。CommissionedClassification含有SalesReceipt。都是采用了组合(composition)方式使用STRATEGY实现支付方式的改变。对于协会成员使用了NULL OBJECT模式。这些模式的使用使得系统很好的符合了OCP,Employee对于支付方式、支付类别、协会从属关系的变化都是封闭的。这样,可以在不影响Employee的情况下,向系统增加新的支付方式,支付类别以及协会从属关系。图18.6成为了我们的核心模型,(core model)或者架构(architecture)。是薪水支付系统所有事情的核心。在薪水支付案例中的其他类和设计,相对于这个基础结构而言都是次要的。当然,这个结构也会和其他部分仪一起演化。第18章薪水支付案例研究:第一次迭代开始-18.2.7发薪日用例7现在运行薪水支付应用程序将薪水计算的任务交付给PaymentClassification。第18章薪水支付案例研究:第一次迭代开始-18.3反思:我们学到了什么用简单的用力分析可以提供丰富以及系统设计的洞察力。图18.6-18.10就是通过思考这些用例得到的,更确切地说,是思考行为得到的。第18章薪水支付案例研究:第一次迭代开始-18.4找出潜在的抽象为了有效的OCP,必须搜寻出隐藏于应用背后的对象。应用需求,甚至用例,不会表达,这些抽象。需求和用例太关注细节以至于不能潜在抽象的一般性。SLS:提炼公用组件也是这个道理。第18章薪水支付案例研究:第一次迭代开始-18.4.1支付薪水时间表抽象支付时间是非常多边的。过度依赖工具和过程低估智力和经验都是灾难的源泉。结果是:增加PaymentSchedule,以及其3个子类对应已知的三种方式。Employee包含了PaymentSchedule。第18章薪水支付案例研究:第一次迭代开始-18.4.2支付方式支付方式的抽象已经从18.6图中表现出来了,他就是PayMethod。第18章薪水支付案例研究:第一次迭代开始-18.4.3从属关系某一雇员可能属于某一协会,但实际是一个雇员可能属于多个协会。结果是Employe持有Affiliation的列表,如果不属于任何协会Affiliation列表,置空即可,不必使用NULL OBJECT模式了。第18章薪水支付案例研究:第一次迭代开始-18.5结论在一次迭代开始,开发团队通常会聚集在一个白板前,一起思考需要实现的用户素材。这类快速设计会话持续时间会小于1小时。也许会产生UML,但最终这些UML不会留在白板上。会话的目的就是发起思考活动,并为开发人员提供一个公共的,可依据其展开工作的智力模型,而不是为了确定设计。本章就是一个快速设计会话的原原本本的例子。第19章薪水支付案例研究:实现本章以微笑增量的方式来创建代码。UML图用于展现我们的想法,为交流提供媒介。图19.1,使用名为Transaction的抽象基类代表操作。采用COMMAND模式,具有execute方法。第19章薪水支付案例研究:实现-19.1增加雇员图19.2,描述AddEmployeeTransaction的上下结构。像往常一样,使用测试优先的方法编写代码:程序19.1.第19章薪水支付案例研究:实现-19.1.1薪水支付系统数据库AddEmployeeTransaction类使用了PayrollDatabase的类,PayrollDatabase中保存了一empID为键值的Dictionary。PayrollDatabase是FACADE模式的列子。程序19.3,19.4该实现是为了帮助通过最初的测试用例。一般而言,我们认为数据库实现是细节。应该尽可能推迟细节的设计决策。不管这个特定的数据库,是RDBMS、平面文件(flat file)、或者OODBMS实现。现在仅对API感兴趣,随后会发现有关数据库的合适实现。推进有关数据库的细节,是一项不常见的、但却很值得的实践。直到对需求有了更多的了解,才进行有关的数据库的决策。通过等待,避免把过多的基础结构放入数据库中。我们仅仅实现刚好实现满足应用程序功能的数据库。第19章薪水支付案例研究:实现-19.1.2使用TEMPLATE METHOD模式来增加雇员图19.4,展示了增加雇员的动态模型。图中,AddEmployeeTransaction向自己发送了一条消息(SLS:调用),其子类实现了这条消息(SLS:方法)。这是一个TEMPLATE METHOD模式的应用。程序19.5、19.6是AddEmployeeTransaction的头文件和cpp文件。程序19.7、19.8是AddSalariedTransaction的头文件和cpp文件。第19章薪水支付案例研究:实现-19.2删除雇员图19.5、19.6中展现了删除雇员操作的静态,动态实现。主要类为DeleteEmployeeTransaction。第19章薪水支付案例研究:实现-19.2.1全局变量对于全局变量GpayrollDatabase,数十年来,教科书和教师一直有好的理由不鼓励使用全局变量。在本例中,使用SINGLETON或MINISTATE模式具有不必要复杂性的臭味。但并不认为全局变量本身是邪恶的,本例中就很适合使用。第19章薪水支付案例研究:实现-19.3时间卡、销售凭条以及服务费用图19.7、19.8展示了时间卡操作的静态和动态结构。主要思路:从PayrollDatabase得到Employee-PaymentClassification,将TimeCard放入其中。将TimeCard放入PaymentClassification中时,需要使用,dynamic_cast操作符。程序19.12为测试用例。程序19.13为TimeCard的实现,目前就是一个数据类。程序19.13为TimeCardTransaction类的实现。其中使用了字符串异常。这不是一个好的长期实践,在抛出异常时很容易出现泄漏内存或资源的代码,要注意。图19.9、19.10展示了向应支付薪水的雇员中登记销售凭条的设计。图19.11、19.12展示了向协会成员等级服务费用的设计。程序19.16为测试用例,第19章薪水支付案例研究:实现-19.3.1代码与UML画UML而没有验证它的代码是很危险的。代码可以告诉你UML不能告诉你的设计内容。在UML中放入不需要的内容,也许总有一天会用上,但在用上之前必须要不断的维护。所以关于员工的会员,我们从对象列表改会NULL OBJECT模式。程序19.17、19.18展示了使用NULL OBJECT模式的ServiceChangeTransaction类的实现。第19章薪水支付案例研究:实现-19.4更改雇员属性图19.3、19.4展示了修改雇员属性的动态结构,SLS:我觉得作者的设计,一直是按照一个操作一个类的方式设计的,如果这样的设计放到很多系统中,肯定会有类爆炸的问题。难道作者没有发现这个问题?图19.15、19.16、19.17展示了改动的动态模型。使用TEMPLATE METHOD模式,从PayrollDatabase取Employee对象的操作在基类中,然后调用自己的change函数,在子类中实现change函数。程序19.19展示了ChangeNameTransaction的测试用例。程序19.20、19.21展示了抽象基类ChangeEmployeeTransaction的实现。一个明显的TEMPLATE METHOD模式。程序19.22、19.23展示了ChangeNameTransaction类的实现。TEMPLATE METHOD模式的另一半。第19章薪水支付案例研究:实现-19.4.1更改雇员类别图19.18-19.21展示了ChangeClassificationTransaction的动态行为。又一个TEMPLATE METHOD模式。程序19.24展示了ChangeHourlyTransaction的测试用例。程序19.24、19.25展示了ChangeClassificationTransaction的实现。TEMPLATE METHOD模式。程序19.26、19.27展示了ChangeHourlyTransaction的实现。TEMPLATE METHOD模式。图19.22-19.28展示了ChangeMethodTransaction、ChangeAffilicationTransaction以及子类的UML图。与ChangeClassificationTransaction的实现是一脉相承的。第19章薪水支付案例研究:实现-19.4.2我当时抽了什么烟了PayrollDatabase应该记录Bill的协会成员关系,但在UML中并没有显示这一点。SLS:也就是说,雇员与协会这件的关系,没有被持久化到数据库中。通过为ChangeAffiliation增加RecordMemership(Employee*)来解决这个问题。SLS:以前的程序19.23 ChangeNameTransaction.cpp,也没有把改动持久化啊?有点迷糊。ChangeUnaffiliationTransaction是一件让人不快的事,在Affiliation放入RecordMemberShip和EraseMemberShip,会解决这个问题,但会让Affiliation知道PayrollDatabase也让人不快。最终保持这个轻微违反OCP的设计。SLS:这块感觉有点学究气。第19章薪水支付案例研究:实现-19.5支付雇员薪水图19.29-19.33展示了支付薪水的动态行为和静态结构。CalculatePay算法依赖于Employee依赖的PaymentClassification,是否支付日期依赖于Empoyee的PaymentSchelue,支付信息依赖于Employee的PaymentMethod。这种高度的抽象,使得,这些算法对于新类型的支付类别、支付薪水的时间、从属关系,以及支付方式,都可以做到封闭。其中引入了登记的概念,也就是计算正确的支付金额,并发送给Employee后,会等级支付信息。这样Calculate的计算方法为从最近的支付日期到指定日期的薪水。第19章薪水支付案例研究:实现-19.5.1我们希望开发人员做商务决策吗登记这个概念,在用户素材中并没有提到,只是我用这个概念解决遇到的问题-担心同一时间,同一日期多次调用Payday方法,所以要确保不会出现多次支付薪水的情况。我并没有咨询客户。实际我做了一个商务决策,我断定,多次运行薪水支付程序,会有不同的结果。其实我应该咨询客户和项目管理人员。在和客户的协商中,我发现等级违反了客户意图。他们希望再次运行以便检查错误。客户说根本不必考虑支付时间以外的时间卡或者销售条。登记方案被抛弃。SLS:作者写这段的意思是,开发人员不应该做商务觉得,要多与客户沟通。第19章薪水支付案例研究:实现-19.5.2支付带薪雇员薪水程序19.36为支付带薪雇员的测试用例。程序19.37为PaydayTransaction:Execute:取得所有Employee,并循环调用IsPayDate方法。程序19.38为Monthshedule.cpp的部分实现。程序19.39为Employee:PayDay()的实现。SLS:注意:PayCheck就是一个数据类。第19章薪水支付案例研究:实现-19.5.3支付钟点雇员薪水支付钟点雇员薪水的实现,是用来说明测优先设计增量型的很好示例。我们会从最简单的测试用例开始,直到更加复杂的测试用例。程序19.40-19.46都为逐步增加复杂度的测试用例,以及HourlyClassification.cpp、WeeklySchedule.cpp的代码片段。第19章薪水支付案例研究:实现-19.5.4支付期:一个设计问题本节实现计算会费和服务费的功能。程序19.47为带薪雇员转变为协会会员后,支付其薪水。问题:用户素材说会费每周提交一次,带薪雇员的薪水是每月支付,一个月包含几周?询问客户得知会费每周五累加一次。将IsInPayPeriod函数放到HourlyClassification,是错误的。用于确定支付期的函数应该属于PaymentSchedule类。UML图并没有帮我们捕捉这个问题,再次说明代码反馈对于设计是多么重要。程序19.48,PaydayTransaction:Execute程序19.49,PaymentClassification:IsInPayPeriod以上两个程序演示了,将IsInPayPeriod从HourlyClassification转移出来的代码。程序19.50,UnionAffiliation:CalculateDeductions(),展示如何计算雇员的会费。程序19.51,为按小时支付雇员的会费扣除的测试用例。程序19.52,验证当前支付之间外的会费没有被扣除。将判断日期是否在某个时间段内的IsInPayPeriod的函数放到了Date中,改名IsBetween。程序19.53程序19.54、19.55展示了Employee.h和Employee.cpp第19章薪水支付案例研究:实现-19.6主程序图19.34、19.35描绘了主程序的静态和动态结构。PayrollApplication处在一个循环之中,交替从TransactionSource获取操作,然后执行。TransactionSource是一个抽象类,可以有各种实现,图中为TextTransactionSource。TransactionSource中接口和实现的分离使操作的来源可以成为抽象的。例如:GUITransactionSource、RemoteTransactionSource第19章薪水支付案例研究:实现-19.7数据库在完成了本次的迭代中的分析、设计、实现工作后,可以考虑数据库了。可以使用OODBMS来实现PayrollDatabase,对应用程序的对象模型没有影响。可以使用平面文件来,实现PayrollDatabase,但对于大量数据或并发访问的应用来讲,则无法满足需求。可以使用RDBMS,实现PayrollDatabase。关键在于,数据库只是管理存储的机制。通常不应该作为设计和实现的主要因素。流到最后,作为细节处理。这样实现持久化功能时,我们就会有很多方案可供选择。也没有和任何数据库或产品绑定,我们可以选择,替换数据库。设计者应该解除设计和数据库之间的耦合,应用设计不应该依赖于任何特定的数据库。SLS:我觉得上边的观点,是极端的面向对象观点,或叫极端的设计观点。实际使用时,这样设计会导致巨大的不必要的复杂性。数据库应用,还是面向数据库比较好。没想到看着面向对象设计的书,却要不使用面向对象设计。首先我们的目的,是为了满足客户需求,而不是做面向对象设计,所以,应该有一套面向数据库的设计方法。我们不应该为了面向对象而去面向对象。就像前边一直有所表述的知道何时不运用运行一个设计原则、模式或最佳实践,比知道如何运用它同样重要,第二章一开始也说,XP并不是唯一的选择。同样,面向对象也不是唯一的选择,或者我们可以选择面向数据库设计?知道何时不运用面向对象设计也同样重要。当然,作者是在讲面向对象设计,不可能突然将,面向数据库方面的设计,但面向数据库的设计也值得研究。第19章薪水支付案例研究:实现-19.8薪水支付系统设计总计由于使用了大量的抽象和多态,使得绝大部分设计对于薪水支付策略更改做了封闭。在这个过程中,我们很少考虑我们是否在进行分析、设计、实现(SLS:意思是没有考虑处于哪个阶段),相反,我们全神贯注于清楚和封闭问题。尽力找出潜在的抽象。最终,我们获得一个薪水支付应用的初始设计,并且拥有了一组在整体上和问题域密切关联的核心类。SLS:对于18章,图18.6薪水支付的核心模型,是通过分析行为得到的静态结构。我觉得这个结构是简洁的。但19章,由于使用了COMMAND模式,导致了类爆炸,增加了复杂性。当然,使用COMMAND也获得了巨大的好处,19.6主程序对这种好处有所阐述。SLS:对于本例,我觉作者的目的,是要获得一组在整体上和问题域密切关联的核心类,所以作者没有考虑数据库和界面。而这种去界面,去数据库的一组核心类是对问题域的高度抽象,由于其巨大的可扩展性,所以在以后的设计中,非常值得借鉴。至于面向数据库设计那是另一码事。第19章薪水支付案例研究:实现-19.8.1历史讲述,本例子的历史,是1994年就创建了图示,并在1995年出版的一本书中使用。但由于当时没有代码反馈,所以犯了一些错误。从而凸显出,代码反馈的重要性。第19章薪水支付案例研究:实现-19.8.2资源第部分打包薪水支付系统本章部分研究把大的软件系统分割成包的设计原则。第20章包的设计原则优美的包裹-安东尼类对于小的应用程序来说是非常方便的组织单元,但对于应用程序规模和复杂度比较高的程序,需要在更高的层次对应用程序进行组织,那就是包。本章讲述6个原则,前三个关注包的内聚性,如何把类划分到包中,后三个关注包的耦合性(确定包之间的关系),最后两个还描述了一组依赖性管理度量,据此对设计中的依赖结构进行度量。第20章包的设计原则-20.1如何进行包的设计UML中包可以是类的容器。把类组织成包,可以在更高的层次理解设计。根据一些原则对应用程序的类进行划分。跨包的类的依赖关系,导致了包之间的依赖关系,这就提出了如下几个问题:1.想包中分配类时应该依据什么原则?2.应该使用什么设计原则管理包之间的关系?3.包的设计应该先于类(自顶向下)?还是类的设计先于包(自底向上)?4.如何实际表现出包?C+中,JAVA中,其他环境5.包创建好后,应该用于何种目的?第20章包的设计原则-20.2粒度:包的内聚性原则本节讲述包的内聚性的三个原则,帮助开发者把类划分到包中。这些原则依赖于:至少存在一些类,并且他们之间的关系已经确定。这些原则是依据自底向上的观点划分的。第20章包的设计原则-20.2.1重用发布等价原则REP重用发布等价原则当重用一个类库时,对这个类库的作者的期望当然是:好的文档、可工作的代码、规格清晰的接口。但除了这些还有:首先,希望代码作者这保证维护代码。其次,希望代码作者计划修改接口和功能等改动时,通知你。但仅仅是通知是不够的,要允许你具有不使用新版本的权利。当不使用新版本时,必须对旧版本继续提供支持。这是一个行政问题。REP指出,一个包的重用粒度可以和发布粒度一样大。重用的东西必须被同时发布和跟踪。简单的声称重用是不够的,要建立一个跟踪系统,为潜在的使用者提供需要的变更通知,安全性,支持后,重用才有可能。REP给我们关于如何把设计划分到包中的第一个提示,由于重用性必须是基于包的,所以可重用的包,必须基于可重用的类,因此该包必须有可重用的类组成。我们必须从重用者的角度考虑包的内容,如果包中的软件是为了可重用的,那么他就不能包含不是为重用目的而设计的软件。一个包中的软件要么都是可重用的,要么都不是可重用的。SLS:为包的使用者提供一个干净的纯粹的用于重用的包。但这好像和共同重用原则一样。对于这个原则,我理解为,重用和发布一样重要。要重用就要配合发布,跟踪等。但这和包的划分有什么关系呢?SLS:网络资料的辅助理解:OO设计模式和设计原则一个可重用的元件(组件、一个类、一组类等),只有在它们被某种发布(Release)系统管理以后,才能被重用。将什么类放在一个包中的判断标准之一就是重用,并且因为包是发布的最小单元,它们同样也是重用的最小单元。体系结构师应该将可重用的类都放在包中。SLS:REP主要讲述重用和发布的关系,同时指出将重用的类都放在包中。CRP是指那些放入包中的可重用的类,都要为了一个目的而重用。第20章包的设计原则-20.2.2共同重用原则CRP一个包中的所有类都应该是共同重用的。如果重用了包中的一个类,那么就要重用包中的所有类。这一原则,决定哪些类放入同一个包中。规定趋向共同重用的类应该属于同一个包。简称CRP。此外,包经常以共享库、DLL、jar等物理表示的形式出现。当我依赖于一个包,我将依赖于包中的每一个类。防止包中与我无关的修改导致重新验证和发行。第20章包的设计原则-20.2.3共同封闭原则CCP包中的所有类,对于同一类性质的变化应该是共同封闭的。一个变化若对一个包产生影响,将对包中的所有类产生影响,而对于其他的包中的类不产生任何影响。简称CCP。这是单一职责对于包的重新规定。这一原则规定,对于包,不应该包含多个引起其变化的原因。在大多数应用程序中,可维护性的重要性要大于可重用性。如果一个应用中的代码必须修改,那么我们更改都集中在一个包中。CCP鼓励由于同样原因而更改的所有类聚集在同一个地方。以减少软件的发布、重新验证、重新发行的工作量。这个原则和开放封闭原则密切相关。但正如我们学的的,100%封闭是不可能做到的,应该有策略的进行封闭。我们设计的系统应该对于我们最常见的变化做到封闭。第20章包的设计原则-20.2.4包的内聚性过去,我们队内聚性的认识,远比上面3个原则所蕴含的简单。我们习惯于认为内聚性,不过是一个模块执行一项并且仅能执行一项功能。在选择共同组织到包中的类时,必须考虑重用性和可开发性之间的相反作用力。这不是一个简单的工作。并且这个作用力是动态的。今天关注可开发行,明天可能关注可重用性。SLS:我理解可开发行为,是一个相对于重用性的概念。就是只关注当前功能的实现。而不是重用。就叫可开发性。可能实际开发效率。如果关注可重用性,从重用多角度增加功能点。SLS:软件行业呼唤可开发性设计,DFD(Design for Developability,可开发性设计)简单说来,可开发性设计就是我们在开发一个软件(相关)产品时,软件的设计应当考虑方便开发人员(大部分情况下就是我们自己)进行开发,或者说在设计时应考虑如何提高开发效率。DFM是Design for Manufacturability(可制造性设计)的简称,主要研究产品本身的物理设计与制造系统各部分之间的相互关系,并把它用于产品设计中以便将整个制造系统融合在一起进行总体优化。DFM可以降低产品的开发周期和成本,使之能更顺利地投入生产第20章包的设计原则-20.3稳定性:包的耦合性原则我们会再次看到,可开发性和逻辑设计之间的冲突,来自技术和行政方面的作用力会影响包的组织结构,这种作用力,还是易变的。第20章包的设计原则-20.3.1无环依赖原则ADP在包的依赖关系图中,不允许存在环。晨后综合症:造成来后,因为其他同事昨晚对代码的修改,导致自己的程序出现问题。在几个开发人员的小项目中,这不是大问题。但当开发团队的规模增长时,就会带来噩梦。在缺乏纪律的团队中,几周都无法构建出一个稳定的项目版本是很常见的。每个人都在忙于修改代码以适应别人的代码。对于这种问题的解决方法有:每周构建,ADP。第20章包的设计原则-20.3.2每周构建每周构建尝尝应用在中等规模的项目中:每周前四天各自工作,互不打扰。周五集成。糟糕的是,随着项目的增长,集成工作量越来越大。从而导致效率下降,导致危机。第20章包的设计原则-20.3.3消除依赖环通过把开发环境划分为可发布的包可以解决上述问题。这些包可以作为工作单元拆分出来。每个工作单元都收版本控制,都有发布。其他团队会可以决定是否采用其他团队的新版本。这是一个非常简单合理的过程,并被广泛使用。要使这个方法起效。包的依赖关系中不能存在环。SLS:上述方法,对每个单元都建立版本,会增加版本控制的工作量,对于超大的项目也许合适。我认为由架构师,从总体的角度划分包,划分包之间的结构,是解决这个这个问题的更好的方法。也许是敏捷开发不允许架构师的存在,所以作者没有提到这个问题。图20.1包结构是有向无环图。这类表明包之间依赖关系的图,非常好。第20章包的设计原则-20.3.4包的依赖关系图中环造成的影响依赖环,会导致这些有依赖关系的包,编程一个大包。从而影响发布,造成相互影响。单元测试和发布非常困难,容易出错。难于确定构建关系。第20章包的设计原则-20.3.5解除依赖环将依赖关系图恢复为DAG的方法:1.使用依赖导致。从客户角度(函数调用者),而不是服务者(函数提供者)的角度命名接口。是接口属于客户规则的又一应用。2.将组成环的包,合并为一个包。第20章包的设计原则-20.3.6抖动第二个方案意味着,在需求改变面前,包的结构是不稳定的。第20章包的设计原则-20.4自顶向下设计现在可以得出结论:不能自顶向下的设计包的结构。这意味着包的结构,不是设计系统首先考虑的事情之一,事实上,包的结构,应该是随着系统的增长、变化而逐步演化的。也许这违反直觉,我们已经认为包这样的大粒度分解,也是高层功能分解。事实上,包的依赖关系图,几乎和描述应用程序功能之间,没有关系。项目开始无软件可构件,就没有关系图。随着项目规模的增长,不断使用SRP、CCP、ADP将同类放到一个包中,关注重用,去掉依赖环。包的依赖关系,是和系统逻辑设计一同增长和演化的。第20章包的设计原则-20.5稳定依赖原则SDP朝着稳定的方向进行依赖设计不能是固定的,设计的可维护和某种程度的易变性是必要的。通过共同封闭原则,我们创建变化敏感型的包,这些包期待变化。对于任何包而言,如果其时可变的,就不能让难于改变的包依赖它。这会导致一边包的难以改变。通过SDP,要确保易于更改的包不会被难于更改的包所依赖。第20章包的设计原则-20.5.1稳定性硬币竖在桌子上,我们认为它是不稳定的。虽然没有人碰他,他不会倒。可见稳定性与变化的频率(不碰硬币他不会动)没有直接关系。韦伯斯特认为:不容易被移动,被认为是稳定稳定性和更改所需要的工作量有关。对于软件来说,被依赖的包越多,那么这个包就应该越稳定。因为依赖关系导致改动的工作量变大。第20章包的设计原则-20.5.2稳定性度量度量一个包的稳定性:计算该包进出依赖关系的数目。不稳定性I=输出耦合度(处于该包内部并依赖该包外类的数目)/输入耦合度(处于该包外部并依赖该包类的数目)+输出耦合度。箭头所指是被依赖者。I=0最大稳定性。C+中,通过计算#include语句表示。java中计算import。SPD规定,一个包的I的度量值应该大于它所依赖的包的I度量值。也即是说I应该顺着依赖的方向减小。第20章包的设计原则-20.5.3并非所有的包都应该是稳定的如果一个系统中所有的包都是最大程度的问题,那么这个系统是不可变的。这并不是希望的事情。我们希望系统中,一些包是稳定的,一些是不稳定的。可变包位于顶部,依赖于底部稳定的包。这样向上的箭头意味着违反SDP。第20章包的设计原则-20.5.4在那里放置高层设计系统中,某些软件并不经常改变,改软件代表系统的高层架构和设计决策。我们希望这些架构觉得是稳定的。然而,如果把高层设计放入稳定的包中,那么体现高层设计的源代码会很难改变,这样又不具有灵活性。怎样具有最高稳定性,又具有灵活性?OCP就是答案,抽象类符合OCP。第20章包的设计原则-20.6稳定抽象原则SAP包的抽象,应该和其稳定程度一致。该原则将稳定性和抽象性联系起来。该规则规定:稳定的包应该是抽象的,这样他的稳定性就不会使其无法扩展。不稳定的包应该是具体的,因为不稳定性使其内部代码易于更改。SDP和SAP在一起,形成了针对包的DIP原则。结论是,依赖应该朝抽象的方向进行。DIP是一个处理类的原则,类没有灰度的概念。类要么是抽象,要么是具体的。第20章包的设计原则-20.6.1抽象性度量抽象性A=抽象类的数目/包中类的总数第20章包的设计原则-20.6.2主序列现在我们定义不稳定性I和抽象性A的关系,创建一个以A为纵轴,I为横轴的坐标图,在坐标图中两种好的包的类型。最稳定最抽象的包位于左上角,最不稳定最具体的包位于右下角。位于(0,0)附近的被称为痛苦地带。高度稳定且具体的。应该注意,数据库模式就是这样的一个例子。数据库模式的异变众所周之(SLS:就算使用数据类,也依然是异变的)并且他是非常具体,高度被依赖的。这就是为什么面向对象应用程序和数据库之间的接口难以定义,以及数据库模式更新通常都很痛苦的原因。还有工具库也位于(0,0)位于(1,1)附近的被称为无用地带,抽象,但不被依赖。主序列:(1,0)至(0,1)的线。(命名来自作者对天文学和HR图(赫罗图横行真实亮度与表面问的的关系)第20章包的设计原则-20.6.3到主序列的距离度量包到主序列的距离。距离D=|A+L-1|/根号二规范化距离D=|A+L-1|使用这个度量,可以全面分析一个设计和主序列之间
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 北欧家装设计知识培训
- 校外骑车安全知识培训课件
- 校园预防偷窃安全知识培训课件
- 辩论修养试题及答案
- 电厂化学考试题及答案
- 北京面部护理知识培训班课件
- 校园安全知识培训教材课件
- 静态代理面试题及答案
- 音标课堂测试题及答案
- 三农培训考试题及答案
- 《用户体验的要素》课件
- 基于现代文献探讨经方治疗冠心病(胸痹心痛)的处方用药规律研究演示稿件
- 钣金结构件点检表
- 一元二次不等式及解法
- 桩基工程验收监理质量评估报告
- 2022年脓毒血症指南解读(更新)
- 郭岩非煤矿山双重预防机制建设课件
- 中医揿针技术理论考核试题
- 第五代移动通信设备安装工程造价编制指导意见(5G补充定额)
- PCB设计检查表-PCB-checklist完整版
- 抗菌药物临床应用指导原则2015年版
评论
0/150
提交评论