单一职责原则SRP·定义就一个类而言,应该仅有一个引起它变化的原因。变化是指具体类的改变,如一个moden类具有连接管理和数据通讯的功能,那么这个类就有连接管理和数据通讯这两个变化方向,此时就违背了“单一职责的原则”。·关于“单一职责”“单一职责”也就是“单一变化原因”。“职责”也就是引起类变化的原因。“单一职责原则”是面向对象设计的第一个基本原则,它可能是最简单的也可能是最难运用的一个原则!通常,一个类的“职责”越多,导致其变化的因素也就越多。因为每个职责都可能是一个变化的轴线。这与我们在设计类时所采用的方法有关系。一般情况下,我们在设计一个类的时候会把与该类有关操作都组合到这个类中,这样做的后果就有可能将多个职责“耦合”到了一块,当这个类的某个职责发生变化时,很难避免类的其它部分不受影响,这最终导致程序的“脆弱”和“僵硬”。解决这种问题的方法就是“分耦”,将不同的职责分别进行封装,不要将其组合在一个类中,使这个类只有一个可能会引起它变化的原因。这样做将会使你的程序易于修改和维护。但这个过程可能是很困难的,因为我们不总是能轻易知道那些职责会发生变化,那些职责应该被提取出来。所以,你的程序可能会有一个演化的过程,从中得出这些会发生的职责并进行另外的封装。需要注意的一点就是当实标情况中的职责确实发生了变化,应用该原则才是有意义的。如果一个类组合了多个职责,但这些职责在实际情况中根本不会发生变化,那完全没有必要提前费尽心机去应用这个原则。总结:SRP好处:消除耦合,减小因需求变化引起代码僵化性臭味注意点:1.一个合理的类,应该仅有一个引起它变化的原因,即单一职责;2.在没有变化征兆的情况下应用SRP或其他原则是不明智的;3.在需求实际发生变化时就应该应用SRP等原则来重构代码;4.使用测试驱动开发会迫使我们在设计出现臭味之前分离不合理代码;4.如果测试不能迫使职责分离,僵化性和脆弱性的臭味会变得很强烈,那就应该用Facade或Proxy模式对代码重构;实例:违反SRP原则代码:modem接口明显具有两个职责:连接管理和数据通讯;classModem{publicvoiddial(stringpno);publicvoidhangup();publicvoidsend(charc);publicvoidrecv();}此时应该把的modem的两个职责分到两个类中classDataChannel{publicvoidsend(charc);publicvoidrecv();}classConnection{publicvoiddial(stringpno);publicvoidhangup();}新的modem类:classmodem{//构造publicmodem(){datachannel=newDataChannel();con=newConnection();}//字段privateDataChanneldatachannel;privateConnectioncon;//操作publicvoiddial(stringpno){datachannel.dial();}publicvoidhangup().......publicvoidsend(charc).......publicvoidrecv().......}一、什么是开放封闭原则开放封闭原则(Open-ClosedPrinciple):一个软件实体应当对扩展开放,则修改关闭。在设计一个模块时,应当使得这个模块可以在不被修改的前提下被扩展。也就是说,应当可以在不必修改源代码的情况下修改这个模块的行为。设计的目的便在于面对需求的改变而保持系统的相对稳定,从而使得系统可以很容易的从一个版本升级到另一个版本。二、怎样做到开放封闭原则实际上,绝对封闭的系统是不存在的。无论模块是怎么封闭,到最后,总还是有一些无法封闭的变化。而我们的思路就是:既然不能做到完全封闭,那我们就应该对那些变化封闭,那些变化隔离做出选择。我们做出选择,然后将那些无法封闭的变化抽象出来,进行隔离,允许扩展,尽可能的减少系统的开发。当系统变化来临时,我们要及时的做出反应。我们并不害怕改变的到来。当变化到来时,我们首先需要做的不是修改代码,而是尽可能的将变化抽象出来进行隔离,然后进行扩展。面对需求的变化,对程序的修改应该是尽可能通过添加代码来实现,而不是通过修改代码来实现。实际上,变化或者可能的变化来的越早,抽象就越容易,相对的,代码的维护也就越容易;而当项目接近于完成而来的需求变化,则会使抽象变得很困难——这个困难,并不是抽象本身的困难,抽象本身并没有困难,困难在于系统的架构已经完成,修改牵扯的方面太多而使得抽象工作变得很困难。三、繁忙的银行业务员四、轻松的银行业务员三、开放封闭原则的优越性1.通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,是变化中的软件有一定的适应性和灵活性。2.已有的软件模块,特别是最重要的抽象模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。没有实现OCP原则的例子:BankWorker.java/**银行业务员*/publicclassBankWorker{//负责存款业务publicvoidsaving(){System.out.println(进行存款操作);}//负责取款业务publicvoiddrawing(){System.out.println(进行取款操作);}//负责转账业务publicvoidzhuanzhang(){System.out.println(进行转账操作);}//负责基金的申购publicvoidjijin(){System.out.println(进行基金申购操作);}}MainClass.javapublicclassMainClass{publicstaticvoidmain(String[]args){BankWorkerbankWorker=newBankWorker();//存款bankWorker.saving();//取款bankWorker.drawing();//转账bankWorker.zhuanzhang();//基金bankWorker.jijin();}}实现了OCP原则的代码例子:BankWorker.javapackagecom.ibeifeng.ex2;/**银行业务员接口,是所有银行业务员的抽象父类。*/publicinterfaceBankWorker{publicvoidoperation();}SavingBankWorker.javapackagecom.ibeifeng.ex2;/**负责存款业务的业务员*/publicclassSavingBankWorkerimplementsBankWorker{publicvoidoperation(){System.out.println(进行存款操作);}}DrawingBankWorker.javapackagecom.ibeifeng.ex2;/**负责取款业务的业务员*/publicclassDrawingBankWorkerimplementsBankWorker{publicvoidoperation(){System.out.println(进行取款操作);}}ZhuanZhangBankWorker.javapackagecom.ibeifeng.ex2;/**负责转账业务的业务员*/publicclassZhuanZhangBankWorkerimplementsBankWorker{publicvoidoperation(){System.out.println(进行转账操作);}}JiJinBankWorker.javapackagecom.ibeifeng.ex2;publicclassJiJinBankWorkerimplementsBankWorker{publicvoidoperation(){System.out.println(进行基金申购操作);}}MainClass.javapackagecom.ibeifeng.ex2;publicclassMainClass{publicstaticvoidmain(String[]args){BankWorkerbankWorker=newSavingBankWorker();bankWorker.operation();BankWorkerbankWorker2=newDrawingBankWorker();bankWorker2.operation();BankWorkerbankWorker3=newZhuanZhangBankWorker();bankWorker3.operation();BankWorkerbankWorker4=newJiJinBankWorker();bankWorker4.operation();}}Liskovsubstitutionprinciple(LSP)–里氏代换原则软件工程大师RobertC.Martin把里氏代换原则最终简化为一句话:“Subtypesmustbesubstitutablefortheirbasetypes”。也就是,子类必须能够替换成它们的基类。即:子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。另外,不应该在代码中出现if/else之类对子类类型进行判断的条件。里氏替换原则LSP是使代码符合开闭原则的一个重要保证。正是由于子类型的可替换性才使得父类型的模块在无需修改的情况下就可以扩展。这么说来,似乎有点教条化,我非常建议大家看看这个原则个两个最经典的案例——“正方形不是长方形”和“鸵鸟不是鸟”。通过这两个案例,你会明白《墨子小取》中说的——“娣,美人也,爱娣,非爱美人也….盗,人也;恶盗,非恶人也。”——妹妹虽然是美人,但喜欢妹妹并不代表喜欢美人。盗贼是人,但讨厌盗贼也并不代表就讨厌人类。这个原则让你考虑的不是语义上对象的间的关系,而是实际需求的环境。在很多情况下,在设计初期我们类之间的关系不是很明确,LSP则给了我们一个判断和设计类之间关系的基准:需不需要继承,以及怎样设计继承关系。TheStableAbstractionsPrinciple(SAP)-OO设计的稳定抽象等价原则2009-02-129:53概要Packagesthataremaximallystableshouldbemaximallyabstract.Instablepackagesshouldbeconcrete.Theabstractionofapackageshouldbeinproportiontoitsstability.最稳定的包应该是最抽象的包。不稳定的包应该是具体的包。包的抽象程度跟它的稳定性成正比。换成另一个说法是:Stablepackagesshouldbeabstractpackages.稳定的包应该是抽象的包。包的稳定抽象等价原则我们在TheStableDependenciesPrinciple(SDP)-OO设计的稳定依赖原则一文中谈到了包的稳定性:不容易改变的包应该具有更好的稳定性。一个包的抽象程度越高,它的稳定性就越高。反之,它的稳定性就越低。一个稳定的包必须是抽象的,反之,不稳定的包必须是具体的。稳定的包的构成抽象类或接口通过子类继承扩展行为,这表示抽象类或接口比它们的子类更具有稳定性。总之,为了构成稳定的包,应该提高包内的抽象类或接口的比率;它们的子类可以放在另一个不稳定的包内,该包依赖上述稳定的包,从而遵循了稳定依赖原则(SDP)。理想的体系结构应该是:不稳定的(容易改变的)包处于上层-它们是具体的包实现稳定的(不容易改变的)包处于下层-不容易改变,但容易扩展-接口比实现(具体的运行代码)在内在特性上更具有稳定性图1:遵循稳定依赖原则(SDP)的理想的体系结构小结稳定抽象等价原则(SAP)为我们解决包之间的关系耦合问题。在设计包结构时,稳定