【SOLID原則】開放/閉鎖原則とは何か

2023/02/26に公開約2,000字

開放/閉鎖原則とは

オープンクローズドの法則とも呼ばれます。SOLID原則のOにあたる部分です。
開放/閉鎖原則は、拡張には開かれ、修正には閉じているべきだという原則です。

つまり、システムに新しい機能が追加された場合に、既存のコードを変更することなくその機能を追加できるようにすることが重要です。(既存の成果物を変更せず拡張できるようにすべき)

悪いコード(原則に反したコード)

以下は、開放/閉鎖原則に違反している例です。

class Shape {
  constructor(public type: string) {}

  area(): number {
    if (this.type === 'rectangle') {
      return this.rectangleArea();
    } else if (this.type === 'circle') {
      return this.circleArea();
    }
  }

  rectangleArea(): number {
    return this.width * this.height;
  }

  circleArea(): number {
    return Math.PI * this.radius ** 2;
  }
}

const rectangle = new Shape('rectangle');
rectangle.width = 10;
rectangle.height = 5;
console.log(rectangle.area());

const circle = new Shape('circle');
circle.radius = 3;
console.log(circle.area());

この例では、Shapeクラスが、特定のタイプの形状(矩形、円など)に関連するロジックを持っています。そのため、新しい形状を追加する場合、Shapeクラスのareaメソッドを変更する必要があります。これは開放/閉鎖原則に違反しています。
Triangleという別のクラスが増えた時にはさらにShapeメソッドを変更する必要が出てきますね。
しかしこの計測メソッドはシステム上で安定して稼働しているので、できれば触りたくないです。

良いコード(原則に則している)

開放/閉鎖原則を遵守するためには、Shapeクラスを抽象クラスにし、各形状のクラスがareaメソッドを実装する必要があります。また、calculateArea関数のような外部の関数を使用して、任意の形状の面積を計算することができます。

abstract class Shape {
  abstract area(): number;
}

class Rectangle extends Shape {
  constructor(public width: number, public height: number) {
    super();
  }

  area(): number {
    return this.width * this.height;
  }
}

class Circle extends Shape {
  constructor(public radius: number) {
    super();
  }

  area(): number {
    return Math.PI * this.radius ** 2;
  }
}

このようにすることで、新しい形状を追加する場合でも、既存のコードを変更することなくシステムを拡張することができます。

class Triangle implements Shape {
  constructor(public base: number, public height: number) {}

  area(): number {
    return (this.base * this.height) / 2;
  }
}

以下のように柔軟に計算することが可能です。

function calculateArea(shapes: Shape[]) {
  let totalArea = 0;
  for (const shape of shapes) {
    totalArea += shape.area();
  }
  return totalArea;
}

console.log(calculateArea([new Rectangle(10, 5), new Circle(3), new Triangle(10, 5)]));

Discussion

ログインするとコメントできます