面向对象设计原则⏹OO原则:◆封装变化之物◆针对接口编码,而不是对实现◆应用程序中的每一个类只有一个改变的理由◆类是关于行为与功能的⏹目的:设计原则形成更可维护更具灵◆使用已被证实的OO设计原则形成更可维护、更具灵活性以及更易扩展的软件Design Principles⏹OCP (The Open-Closed Principle) 开放-封闭原则SRP(The Single Responsibility Principle)单职责原则⏹SRP (The Single-Responsibility Principle) 单一职责原则⏹LSP (The Liskov Substitution Principle) Liskov替换原则⏹DIP (The Dependency-Inversion Principle) 依赖倒置原则⏹ISP (The Interface-Segregation Principle) 接口隔离原则⏹CARP (Composition/Aggregation Principle ) 合成/聚合复用原则⏹LoD(Law of Demeter) 迪米特法则Open-Closed Principle⏹开-闭原则(Open-Closed Principle)对扩展开放对修改关闭◆对扩展开放,对修改关闭◆OCP允许改变,以不需要修改现有程序代码的方式进行SRP⏹单一职责原则(SRP)就一个类而言,应该仅有一个引起它变化的原因。
◆就个类而言,应该仅有个引起它变化的原因。
Example: SRP violationinterface Modem{public void dial (String pno);ti public void dial (String pno);public void hangup();public void send (char c);public char recv();}connection management data communicationExampleSeparated modem interfaceQuestion AnswerLSP: Liskov替换原则⏹Subtypes must be substitutable for their base types. 子类型必须能够替换掉它们的基类型。
⏹If for each object o1of type S there is an object o2 oftype T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1issubstituted for o2then S is a subtype of T.[Liskov88]LSP Violation (I)struct Shape{enum ShapeType{square circle}enum ShapeType {square, circle}itsType;Shape(ShapeType t):itsType(t){ }};struct Circle: public Shape{ Circle():Shape(circle){ }; void Draw() const;void DrawShape(const Shape& s ){ if(s.itsType == Shape::square){static_cast<const Square&>(s).draw()};struct Square: public Shape{ Square():Shape(circle){ }; void Draw() const;};else if (s.itsType == Shape::circle)static_cast<const Circle&>(s).draw() }RTTI(Run-Time TypeIdentification)LSP Violation (II)class Rectangle{blipublic:void SetWidth(double w) {itsWidth=w;}void SetHeight(double h) {itsHeight=h;}…private:d bl it Widthdouble itsWidth;double itsHeight;…}IS-A RelationshipLSP Violation (II)void Square::SetWidth(double w){Rectangle::SetWidth(w);Rectangle::SetHeight(w):}void Square::SetHeight(double w){ Rectangle::SetWidth(w);Rectangle::SetHeight(w):void f (Rectangle& r){ r.SetWidth(32);}}:SquareViolated!LSP Violation (II)class Rectangle{Are Rectangle and Squareself-consistent? public:virtual void SetWidth(double w) {itsWidth=w;}virtual void SetHeight(double h) {itsHeight=h;}…private:double itsWidth;void g (Rectangle& r){r.SetWidth(5);r SetHeight(4);:SquareTdouble itsWidth;double itsHeight;…}r.SetHeight(4);assert(r.Area()==20);}Trueorfalse?Violated!启发⏹Violation 1:Degenerate functions in derivatives◆Degenerate functions in derivatives 派生类中的退化函数⏹Violation 2:◆Throwing exceptions from derivatives 从派生类中抛出异常LSP⏹One of the enablers of the OCPIt is the substitutability of subtypes that allows a⏹It is the substitutability of subtypes that allows amodule, expressed in terms of a base type, to beextensible without modification.DIP 依赖倒置原则⏹High level modules should not depend on low-levelmodules Both should depend on abstractions modules. Both should depend on abstractions. 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
⏹Abstractions should not depend on details. Details should depend on abstractions. 抽象不应该依赖于细节,细节应该依赖于抽象。
⏹Inversion: 相对于结构化方法而言Laying⏹Booch: “… all well structured OO architectures have clearlydefined layers with each layer providing some coherent set of defined layers, with each layer providing some coherent set of services through a well-defined and controlled interface.”Unfortunate!Laying⏹Inverted layers Hollywood principle: “don’t call us, we’ll call,you.”also an inversion of interface ownership: 客户拥有抽象接口,服务者则从这些抽象接口派生。
启发⏹“Depend on abstractions”should not depend on a concrete class–that all◆should not depend on a concrete class that allrelationships in a program should terminate on anabstract class or an interface.⏹According to it:◆No variable should hold a pointer or reference to aconcrete class.No class should derive from a concrete class◆No class should derive from a concrete class.◆No method should override an implementedmethod of any of its base classes.DIP⏹If its dependencies are inverted, it has an OO design Otherwise it has a procedure design⏹Otherwise, it has a procedure design.⏹LSP is the fundamental low-level mechanism behindmany of the benefits claimed for OO technology.ISP 接口隔离原则⏹Clients should not be forced to depend on methodsthat they do not usethat they do not use. 不应该强迫客户依赖于它们不用的方法。
⏹Deals with the disadvantage of “fat” interfaces –whose interfaces are not cohesive.Exampleclass Timer {common door!class Door {public:virtual void Lock() = 0;virtual void Unlock() = 0;virtual bool IsDoorOpen() = 0; }public:void Register (int timeout,TimeClient* client );}class TimerClient {public:virtual void TimeOut () = 0; }How about a timed door?Interface PollutionBut not all varietiesof Door need timing!Separate InterfacesSolution 1: adapterTimer +TimeOut()Timer Client *0..*DoorTimed DoorDoor Timer Adapter +DoorTimeOut()+TimeOut()*0..*class TimedDoor: public Door{public: virtual void DoorTimeOut(int timeoutId);}Class DoorTimerAdapter: public TimeClient {pubic:DoorTimerAdapter(TimedDoor& theDoor): itsTimedDoor(theDoor){} virtual void TimeOut(int timeoutId){itsTimedDoor.DoorTimeOut(timeoutId);}private:TimedDoor& istTimedDoor;}Separate InterfacesSolution 2: multiple inheritanceclass TimedDoor: public Door, publid TimerClient{public: virtual void TimeOut(int timeoutId);}CARP⏹别名:Composite Reuse Principle 合成复用原则)vs Aggregation(⏹Composition(合成) vs. Aggregation(聚合)◆聚合表示“拥有”关系或者整体与部分的关系◆合成是一种强得多的“拥有”关系——部分和整体的生命周期是一样的。