|
||||
|
週刊オブジェクト倶楽部 2003-01号の書評『オブジェクト指向入門』の中で、OCP"Open-Close Principle"として、 「ソフトウェアモジュールは、変更に対して閉じており、拡張に対して開いているべき」 を紹介しました。第1回目は、このOCP からです。次のC言語コードを見てどう思いますか? [コード1]
typedef struct { int x, y; } Point;
typedef struct { Point p1, p2; } Line;
typedef enum { LINE, POINT } Kind;
typedef union { Point* point; Line* line; } ShapeUnion;
typedef struct {
Kind kind;
ShapeUnion of;
} Shape;
void draw(Shape* shape) {
switch(shape->kind) {
case LINE:
/* draw line (shape->of->line.p1 ---- shape->of->line.p2) */
break;
case POINT:
/* draw point (shape->of->point)*/
break;
}
}
これは、私が15年前に書いたコードです。なかなかイケてるでしょ?
でも、Kindとして新たにCIRCLEを追加したとき、このdraw関数を修正し、
case CIRCLEを追加しなければならいのです。では、どうするの?C++では、 [コード2]
class Shape {
public:
virtual void draw() = 0;
};
class Point : public Shape {
int x, y;
public:
void draw() { /* draw point (x,y) */ }
};
class Line : public Shape {
Point p1, p2;
public:
void draw() { /* draw line p1-p2 */ }
};
と書くことができます。このようにすると、Circleの追加は、「既存のプログ
ラムを全く変更せずに」(再コンパイルさえも!)できるのです。これが、
CloseしているプログラムをOpenにするというオブジェクト指向プログラミング
の1つの真骨頂なのです。修正の論理を、追加の論理に変換している、といえます。ちなみに、オブジェクト指向プログラミングでは、構造化プログラミングで gotoが悪だったように、switch分岐は悪と言われています。 (2箇所以上同じ分岐がある場合)。 後日談。 現在では、『リファクタリング』という再設計技術が注目されるようになり、 コード1をコード2に再設計することを、Replace Conditional With Polymorphism (多態による条件分岐の置き換え)と呼んでいます。また、switch文が必ずしも 悪という訳ではなく、同じパターンのswitchが繰り返されることが悪だ、と いう解釈になっています。(Once and Only Onceの原則) |
||||
| つづき |
