Anda di halaman 1dari 2

Open-Closed Principle, OCP Software entities (classes, functions, etc.

.) should be open for extension, but closed for modification.


Procedural Solution to the Square/Circle Problem (violates OCP, Open-Closed Principle) enum ShapeType {circle, square}; struct Shape { ShapeType itsType; }; struct Circle { ShapeType itsType; double itsRadius; Point itsCenter; }; struct Square { ShapeType itsType; double itsSide; Point itsTopLeft; }; // the procedural solution

// These functions are implemented elsewhere 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; } } }

OOD solution to Square/Circle problem.


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; }; void drawAllShapes(vector<Shape*>& list) { for (Iterator<Shape*>i(list); i; i++) (*i)->draw(); }

Shape with ordering methods


But what if drawAllShapes should draw all Circles before any Squares. The function drawAllShapes is not closed under these conditions and in general, there is always some kind of change that it is not closed under. Since closure cannot be complete, it must be strategic. The designer must choose the kinds of changes against which to close the design. The experienced designer knows the users and the industry well enough to judge the probability of different kinds of changes. The open-closed principle is invoked for the most probable changes. Closure is based on abstraction so some kind of ordering abstraction is needed. class Shape { public: virtual void draw() const = 0; virtual bool precedes(const Shape&) const = 0; bool operator<(const Shape& s) {return precedes(s);} }; void drawAllShapes(vector<Shape*>& list) { // copy elements and sort vector<Shape*> orderedList = list; orderedList.sort(); for (...) (*i)->draw(); } // orders all circles before squares bool Circle::precedes(const Shape& s) const { return dynamic_cast<Square*>(s); // true if s is a Square } This function does not conform to the open-closed principle either as there is no way to close it against new derivatives of Shape. Every time a new derivative of Shape is created, this function will need to be changed.

Using a data-driven approach


class Shape { public: virtual void draw() const = 0; virtual bool precedes(const Shape&) const = 0; bool operator<(const Shape& s) {return precedes(s);} private: // table of class names defining the order in which shapes are to be drawn }; bool Shape::precedes(const Shape& s) const { // initialization string thisName = // class name of this object string sName = // class name of parameter object int thisNameOrdering = -1, sNameOrdering = -1; // search the table defining order for (int i=0; !at end of table; i++ ) { if (thisName == table[i]) thisNameOrdering = i; if (sName == table[i]) sNameOrdering = i; } return thisNameOrdering < sNameOrdering; } So drawAllShapes is closed against ordering. The only item not closed is the table itself (which can be isolated).

Anda mungkin juga menyukai