⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ood.txt

📁 ears-0.32, linux下有用的语音信号处理工具包
💻 TXT
📖 第 1 页 / 共 3 页
字号:
			  Principles of OOD(author is Robert Martin, check his page on www://www.oma.com/ )--------------------------------------------------------------------   1. Software entities (classes, modules, etc) should be open for      extension, but closed for modification.  (The open/closed      principle -- Bertrand Meyer)--------------------------------------------------------------------The open/closed principle is the single most important guide for anobject oriented designer.   Designing modules whose behavior can bemodified without making source code modifications to that module iswhat yields the benefits of OOD.Consider the following:class Shape                 {public: virtual void Draw() const = 0;};class Square : public Shape {public: virtual void Draw() const;};class Circle : public Shape {public: virtual void Draw() const;};typedef Shape *ShapePointer;void DrawAllShapes(ShapePointer list[], int n){  for (int i=0; i<n; i++)    list[i]->Draw();}Notice that the function 'DrawAllShapes' need not be modified when newkinds of shapes are added to the Shape hierarchy.  In fact, thefunction need not even be recompiled.Yet, even though I don't make changes to the module, I *can* changeits behavior.  Although the function currently only draws circles andsquares, I can enhance it to draw any other shape at all, so long asthat shape is represented by an object that derives from the classShape.So, I can extend the behavior of the module 'DrawAllShapes', withoutmodifying it at all.Now, consider how this would have been done in a language like C.enum ShapeType {circle, square};struct Shape  {ShapeType itsType;};struct Circle {ShapeType itsType; double itsRadius; Point itsCenter;};struct Square {SahepType itsType; double itsSide; Point itsTopLeft;};void DrawSquare(struct Square*);void DrawCircle(struct Circle*);typedef struct Shape *ShapePointer;void DrawAllShapes(ShapePointer list[], int n){  int i;  for (i=0; i<n; i++)  {    struct Shape* s = list[i];    switch (s->itsType)    {    case square:      DrawSquare((struct Square*)s);    break;    case circle:      DrawCircle((struct Circle*)s);    break;    }  }}It should be very clear that the 'DrawAllShapes' function, as writtenin C, cannot be extended without direct modification.  If I need tocreate a new shape, such as a Triangle, I must modify the'DrawAllShapes' function.This, by itself, would not be too bad.  However, in a complexapplication the switch/case statement above is repeated over and overagain for every kind of operation that can be performed on a shape.These statements are difficult to find, and it is easy to makemistakes when modifying them.Worse, every module that contains such a switch/case statement retainsa dependency upon every possible shape that can be drawn, thus,whenever one of the shapes is modified in any way, the modules allneed recompilation, and possibly modification.A major factor in software maintenance is the fact that for everychange that is made, there is a risk that bugs will be introduced.This wreaks havoc with managers and users because old features thatused to work just fine will sometimes break when a new, and apparentlyunrelated, feature is added.However, when the majority of modules in an application conform to theopen/closed principle, then new features can be added to theapplication by *adding new code* rather than by *changing workingcode*.  Thus, the working code is not exposed to breakage.  Thiscreates a significant amount of isolation between features, and allowsfor much easier maintenance.--------------------------------------------------------------------   2. Derived classes must be usable through the base class interface      without the need for the user to know the difference.  (The      Liskov Substitution Principle)--------------------------------------------------------------------This rule is a logical extension of the open/closed principle.Consider function F that uses type T.  Given S a subtype of T, Fshould be able to use objects of type S without knowing it.  In fact,any subtype of T should be substitutable as an argument of F.  If thiswere not true, then F would have to have tests to determine which ofthe various subtypes it was using.  And this breaks the open/closedprincipleFor example:  Consider the problem of the Square and the Rectangle.Mathematically a Square *is* a Rectangle.  This tempts us to invokeinheritance between them:        class Rectangle        {          public:            Rectangle(const Point& tl, double h, double w)            : itsTopLeftPoint(tl)            , itsHeight(h)            , itsWidth(w)            {}            virtual void SetHeight(double h) {itsHeight=h;}            virtual void SetWidth(double w)  {itsWidth=w;}            virtual double GetWidth()  const {return itsWidth;}            virtual double GetHeight() const {return itsHeight;}          private:            Point itsTopLeftPoint;            double itsHeight;            double itsWidth;        };        class Square : public Rectangle        {          public:            Square(const Point& tl, double s)            : Rectangle(tl, s, s)            {}            virtual void SetWidth(double w)            {              Rectangle::SetWidth(w);              Rectangle::SetHeight(w);            }            virtual void SetHeight(double h)            {              Rectangle::SetWidth(h);              Rectangle::SetHeight(h);            }        };In the example above, Square inherits from Rectangle, but thefunctions of Square are overridden to enforce that the height andwidth of the Rectangle are always the same.Now, consider a function which takes a Rectangle as an argument, andadjusts its width so that it has an aspect ratio of 1/2.  i.e. thewidth is half the height.        void HalfAspect(Rectangle& r)        {           r.SetWidth(r.GetHeight()/2);        }This function fails, rather dismally, if a Square is passed into it asfollows:        Square s;        HalfAspect(s); // this just shrinks both sides by 2Since a user of Rectangle can malfunction when passed a Square, Squareis not substitutable for Rectangle.  To make a general fix, we wouldhave to add code to HalfAspect to test the incoming Rectangle to seeif it was a Square:        void HalfAspect(Rectangle& r) throw(BadType)        {           if (typeid(r) == typeid(Square))               throw BadType;           r.SetWidth(r.GetHeight()/2);        }And this creates a dependency upon Square.  Moreover, every time a newunsubstitutable derivative of Rectangle is created, a new test must beadded to all functions that would malfunction.   This violates theopen/closed principle.--------------------------------------------------------------------   3. Details should depend upon abstractions.  Abstractions should      not depend upon details.  (Principle of Dependency Inversion)--------------------------------------------------------------------This is the direction that all dependencies should take in an objectoriented program.  All high level functions and data structures shouldbe utterly independent of low level functions and data structures.Consider a program that controls a home furnace.    Furnace()    {        while(;;)        {            while (ReadTemp() > theMinTemp)                wait(1);            StartFurnace();            while (ReadTemp() < theMaxTemp)                wait(1);            StopFurnace();        }    }This is clearly a simple minded algorithm, but it will serve todemonstrate our point.  Notice that this algorithm will apply to anyfurnace at all.  Thus this high level algorithm is an abstraction, itis independent of the type of furnace we have.However, most of the time, programmers will take a high level policyand code it in terms of the low level details.    #define THERMOMETER 0x86    #define FURNACE     0x87    #define FURNACE_ON  0x01    #define FURNACE_OFF 0x00    Furnace()    {        while(;;)        {            while (in(THERMOMETER) > theMinTemp)                wait(1);            out(FURNACE, FURNACE_ON);            while (in(THERMOMETER) < theMaxTemp)                wait(1);            out(FURNACE, FURNACE_OFF);        }    }It should be pretty clear that this high level function is polluted bythe details of the actual furnace controller.  In fact, theabstraction depends upon the details.It should also be clear that this function cannot be reused with adifferent kind of furnace.  When abstractions depend upon details, theabstractions cannot be reused.We might think that we can improve this by employing structured designas follows:    #include "furnace.h"    Furnace()    {        while(;;)        {            while (ReadTemp() > theMinTemp)                wait(1);            StartFurnace();            while (ReadTemp() < theMaxTemp)                wait(1);            StopFurnace();        }    }    --------------furnace.h------------    double ReadTemp();    void StartFurnace();    void StopFurnace();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -