当前位置:文档之家› 敏捷软件开发

敏捷软件开发

敏捷软件开发:SRP单一职责原则(2009-03-24 20:30:24)转载标签:it这条原则实际就是体现内聚性原则的体现,一个模块的组成元素之间的功能相关性。

把内聚性概念扩展一下:把内聚性和引起一个模块或者类改变的作用力联系起来。

一个类应该只有一个发生变化的原因。

若Game类有2个不同的职责,一个是记录当前轮,另一个式计算分数,最后要把这两个职责分离到两个类中。

为何把这两个职责分在单独的类中呢?因为每个职责都是变化的一个轴线,当需求变化会反映为类的职责的变化。

如果一个类承担了多于一个职责,那么引起它变化的原因就会有多个。

如果一个类承担的职责太多,就等于把这些职责耦合在一起了。

一个职责的变化可能会削弱或抑制这个类完成其他职责的能力,这种耦合或导致脆弱的设计,当变化发生时,设计会遭受到预想不到的破坏。

定义职责:如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责,有时候我们很难注意到这点,我们习惯以组的形式去考虑职责。

public interface Modem{public void Dial(String pno);public void Handup();public void Send(char c);public char Recv();}接口包括了2个职责,第一个职责是连接管理,第二个职责是数据通信。

如果应用程序的变化方式总是导致这两个职责同时变化,那么就不要分离他们,分开他们就会有不必要的复杂性味道。

仅当变化发生时,变化的轴线才有实际意义,如果没有征兆,那么应用SRP或者任何其他原则都是比明智的。

分离耦合的职责:经常会有一些和硬件或者操作系统的细节有关的原因,迫使我们把不愿意耦合在一起的东西欧和在一起了。

然而,对于应用的其余部分来说,通过分离他们的接口我们已经解耦概念。

如果ModenImplementation implemet DataChannel,Conection。

ModenImplementation看起来是一个混杂物,或者有缺陷的类,所有的依赖关系都是从它发出来的。

谁都不需要依赖它,谁都不需要知道它的存在。

因此,我们已经把丑陋的部分隐藏起来了。

其丑陋性不会泄露出来,污染应用程序的其它部分。

持久化:如Emplyee:CalculatePay,Store,Emplyee类包括了业务规则和对于持久化的控制,这两个职责在大多数情况下绝不应该混合在一起。

业务规则往往会频繁地变化,而持久化的方式却不会如此频繁的变化,并且变化的原因也不一样。

把持久化系统和业务规则绑定在一起是自讨苦吃的做法。

如果发现这种情况存在了,应该使用FACADE、dao或者proxy模式对设计进行重构,分离这两个原则。

SRP是所有原则中最简单的原则之一,也是最难正确运用的原则之一。

敏捷软件开发——开放封闭原则OCP首先,让我们分析一下背景。

什么是软件开发过程中最不稳定的因素?——答案是需求!需求在软件开发过程中时时刻刻都可能发生变化。

那么,如何灵活应对变化是软件结构设计中最重要也是最困难的一个问题。

好的设计带来了极大了灵活性,不好的设计则充斥着僵化的臭味。

这样,也就引出了本文的主题:【开发封闭原则】。

下面,就来简单扼要的介绍一下什么是【开放封闭原则】。

【开发封闭原则】包括两个特征:对于扩展是开放的;对于修改是封闭的。

对于扩展开放,意味着模块的行为是可扩展的。

对于修改封闭,就是说在扩展模块行为的同时不对任何既有代码或二进制代码(.jar)进行修改。

当然,这里说的过于绝对。

有时为了完成某些任务不得不改动既有代码。

但是,我们的目标是尽量的遵守原则。

那如何才能做到对扩展开发,对修改封闭呢?关键在于抽象!那什么是抽象呢?我个人的理解是:抽象是对事物本质的概念上的理解。

面向对象的分析中应该以行为分析为主线。

举一个例子说明:假如从北京到上海,我们可以坐飞机,可以坐火车,可以坐汽车,也可以骑自行车。

那对于这个问题如何分析呢?这个问题的抽象又是什么呢?也许可以这样思考:飞机、火车、汽车和自行车在本质上都是交通工具。

所以得到这样的分析结果:交通工具被抽象为父类,飞机、火车、汽车和自行车都是其特例化的实现,父类中定义一个抽象方法,可以将人从一个地方运送到另外一个地方,各个子类重新定义运送的方式。

这个设计无可厚非!但是,注意了!如果哪天某个人心情不错,想从北京走到上海了。

那他的交通工具又是什么呢?11路!如果把步行也算成交通工具那就太不符合实际了。

所以,面向对象的分析角度,不应该是从事物物理方面的关联去分析,而应该是从事物的行为方面的管理区分析。

对于这个问题,一个人从北京道上海,无论是怎么到达的,只不过是移动策略不同。

下面,就给出相应的示例代码来说明一下上述问题。

class Traveller {private Car car = new Car();public void travel(Address srcAddress,Address destAddress){car.move(srcAddress,destAddress);}}这是最开始直接使用Car的旅行者,如果想替换成AirPlane怎么办?修改代码,用new AirPlane()代替Car。

面向对象的实践原则指出:面向接口编程,而不面向实现编程。

当代码依赖于具体实现时,就缺失了灵活性,面对新的扩展(也就是新的实现),必须修改既有代码。

接着,给出设计灵活的代码:class Traveller {private TravelStrategy _strategy;public void travel(Address srcAddress,Address destAddress){_strategy.move(srcAddress,destAddress);}public void setTravelStrategy(TravelStrategy strategy){_strategy = strategy;}}public interface TravelStrategy{void move(Address srcAddress,Address destAddress);}public class CarStrategy implements TravelStrategy{public void move(Address srcAddress,Address destAddress){...}}public class AirPlaneStrategy implements TravelStrategy{public void move(Address srcAddress,Address destAddress){...}}public class WorkStrategy implements TravelStrategy{public void move(Address srcAddress,Address destAddress){...}}使用这种设计就能灵活的应对设计。

比如说:现在需要另外一种从北京到上海的方式——爬。

呵呵,也许这种行为不可思议,但它也能达到目的。

那如何扩展呢?只需要扩展一个新的TravelStrategy实现即可。

这样,Traveller类不需要修改任何代码!可以通过调用setter方法来切换移动策略。

现在还有一个问题:如何确定实例化哪个策略?这里可以引用工厂,专门负责对象实例化。

可以将需要使用的策略放在文件中,这样改变策略时就不需要修改源代码了。

但当新增策略时,还是需要修改Factory。

没办法,现实中没有完全符合原则的情况,我们只能尽力去遵守!现在,我们看一下以上代码中类之间的关系。

Traveller类、TravelStrategy接口及其实现类,Traveller类是TravelStrategy接口的客户代码。

那Traveller和TravelStrategy的关系与TravelStrategy和它的实现类指尖的关系哪个更紧密一些呢?答案是前者。

这也正是另外一个敏捷原则【依赖倒置原则】。

高层代码不应该依赖低层代码,低层代码要依赖于高层代码。

在这里,说白了的意思就是:一个旅行者要从北京到上海,而旅行团已经给他安排好了去的方法,他本身并不关心怎么到达,只需要知道有办法到达就可以了。

这里旅行者和到达方法之间的关系就非常密切了,而具体如何到达那是低层次的问题了。

上述的问题与实现是实现【开放封闭原则】的一种常用方法——策略模式。

还有一种常用的实现方法:模板方法。

其实,对于这两种方法的本质所在也就是面向对象中的组合与继承。

我们已经学会了如何封装变化,那合适才封装呢?掌握了这项技能是一件好事,但滥用就出问题了~!因为遵循OCP的代价是昂贵的,创建正确的抽象是要花费时间和精力的,同时那些抽象也增加了软件设计的复杂性。

通常,我们采用这种办法:只受愚弄一次。

也就是说,最初的实现不封装任何东西。

当真正的变化到来了,重构代码,封装变化,以避免同类问题再次发生。

OCP是面向对象设计的核心所在。

开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象。

拒绝不成熟的抽象与抽象本身一样重要。

最后,在简单介绍一下面向对象分析的常用方法:寻找问题域中的各个事物或行为共性从共性中创建抽象从共性的变化中创建派生看共性之间的关系如何敏捷软件开发读书笔记(4)——OO五大原则(3.LSP——里氏替换原则)(转)2007-05-31 09:12:06| 分类:J2EE学习 | 标签:无|字号订阅OCP作为OO的高层原则,主张使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。

“抽象”是语言提供的功能。

“多态”由继承语义实现。

如此,问题产生了:“我们如何去度量继承关系的质量?”Liskov于1987年提出了一个关于继承的原则“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“继承必须确保超类所拥有的性质在子类中仍然成立。

”也就是说,当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-A关系。

该原则称为Liskov Substitution Principle——里氏替换原则。

林先生在上课时风趣地称之为“老鼠的儿子会打洞”。

^_^我们来研究一下LSP的实质。

学习OO的时候,我们知道,一个对象是一组状态和一系列行为的组合体。

状态是对象的内在特性,行为是对象的外在特性。

相关主题