🐸

【SOLID原則】オープン・クローズドの原則 - OCP

2021/06/14に公開

SOLID原則とは、ソフトウェア設計の5つの原則の頭字語を取ったものです。ソフトウェアをより理解しやすく、より柔軟に、よりメンテナナンス性の高いものにするために考案されました。

  1. 単一責任の原則(Single Responsibility Principle)
  2. オープン・クローズドの原則(Open/closed principle)
  3. リスコフの置換原則(Liskov substitution principle)
  4. インターフェース分離の原則(Interface segregation principle)
  5. 依存性逆転の原則(Dependency inversion principle)

今回はSOLID原則のひとつ、オープン・クローズドの原則についてです。

オープン・クローズドの原則

オープン・クローズドの原則について、書籍「アジャイルソフトウェア開発の奥義」では、このように書かれています。

ソフトウェアの構成要素(クラス、モジュール、関数など)は拡張に対しては開いて(オープン:Open)いて、修正に対して閉じて(クローズド:Closed)いなけばならない[1]

つまり、ソフトウェアの振る舞いは既存の成果物を変更せず、新たにコードを追加するだけで対応できるようにするべき、ということです。

次のコードはオープン・クローズドの原則に違反しています。このコードを実行すると動物の鳴き声を出力しますが、猫と犬以外に新たに動物を追加したいとき、AnimalSound関数に対して条件分岐を追加しなければいけません。

そのため既存の成果物(AnimalSound関数)に対して、コードを変更せざるを得ません。

class Animal {
    animalName: string
    constructor(name: string) {
        this.animalName = name
    }
}

const AnimalSound = (animal: Animal[]) => {
    for (let i = 0; i < animal.length; i++) {
        if (animal[i].animalName === 'cat') console.log('meow')
        if (animal[i].animalName === 'dog') console.log('bowwow')
    }
}

const animals: Animal[] = [new Animal('cat'), new Animal('dog')]

AnimalSound(animals) // meow bowwow

それでは、オープン・クローズドの原則に従うには、どのようにすべきでしょうか。

それは、各動物に対するクラスを作成し、インターフェースを実装します。新しい動物を追加するときは、新しいクラスを作成するだけになり、既存のAnimalSound関数に手を入れなくて良くなります。

interface IAnimal {
   makeSound(): string
}

class Cat implements IAnimal {
    makeSound = () => 'meow'
}

class Dog implements IAnimal {
    makeSound = () => 'bowwow'
}

const AnimalSound = (animals: IAnimal[]) => {
    for (let i = 0; i < animals.length; i++) {
        console.log(animals[i].makeSound())
    }
}

const animals = [new Cat(), new Dog()]

AnimalSound(animals)

これでオープン・クローズドの原則に従うことが出来ました。既存の処理に手を入れないで仕様変更が出来るため、保守性や柔軟性といったメリットを享受出来ました。

脚注
  1. Robert C. Martin. アジャイルソフトウェア開発の奥義 ↩︎

Discussion