🐷

"いい"コードとは 1(SOLIDの原則 S O 編)

に公開

SOLIDの原則

オブジェクト指向プログラミングにおいて、変更しやすい、理解しやすいコードになるための原則を、

SOLIDの原則

という。

それぞれ、

  • S: Single Responsibility Princeple (単一責任の原則)
  • O: Open-Closed Principle (オープン・クローズドの原則)
  • L: Liskov Substitution Principle (リスコフの置換原則)
  • I: Interface Segration Principle (インタフェース分離の原則)
  • D: Dependency Inversion Principle (依存関係逆転の原則)

という。

今回はこれらの概要を説明していこうとおもう。

Single Responsibility Princeple (単一責任の原則) とは

概要

これは簡単に言えば、「一つのものに一つの責任(役割)を」といった原則である。

とはいっても、そんな簡単な話ではなく、「責任が一つであることってなんだよ」
って話。そもそも見方によって責任なんて変わる。

じゃあどうすんだよ

結論から言うと、、、「変更され得る設計上の選択を分離する」

といったほうが飲み込みやすい。

我々プログラマーは、ドメインが複雑なとき、どんな設計をすればいいかわからない時がある。
そんな中でも、どれか一つを選び、実装する必要がある。

結局、単一責任の原則で何をやりたいかというと、新しい機能や仕様変更の時に、煩わしくないようにしようという目的である。

ここでいう最善の選択とは、

最小限の手直しで変更が可能となるように分けておく

というところにつながるのではないか。

Open-Closed Principle (オープン・クローズドの原則)

概要

これは

既存のコードには修正を加えずに、新しくコードを追加するだけで対応できる設計

にしようという原則である。

これに関しては具体例を見たほうが早い。

わんにゃん村では、毎日いろんな動物にごはんをあげているよ!

class DogFeeder {
  feed() {
    console.log("🐶 わんこにドッグフードをあげたよ!");
  }
}

これがわんこ用のごはんマシンだ!

でもここで急ににゃんこ用のごはんマシンも作りたくなったよ!

class DogFeeder {
  feed(animal) {
    if (animal === "dog") {
      console.log("🐶 わんこにドッグフードをあげたよ!");
    } else if (animal === "cat") {
      console.log("🐱 にゃんこにキャットフードをあげたよ!");
    }
  }
}

こんなことをしていたら最終的にとんでもないことになるのは想像に難くない。

具体的にどうすればいいの?

じゃあどうするのかっていうと、
オープン(拡張OK)クローズド(修正NG)な設計
に変更するには、

interface Feeder {
  feed() {
  }
}
class DogFeeder implements Feeder {
  feed() {
    console.log("🐶 犬にドッグフードあげたよ!");
  }
}
class CatFeeder implements Feeder {
  feed() {
    console.log(🐱 にゃんこにキャットフードをあげたよ!");
  }
}

これで、ウサギが追加されたときでも、

class RabbitFeeder implements Feeder {
  feed() {
    console.log(🐰 うさぎににんじんをあげたよ!);
  }
}

周りのコードを壊す可能性がなくなる。

今はまだ簡単な処理なので、コード量が増えてるし、こんなことをする意味があるのかと感じるだろうが、そもそも壊れる壊れないの話では無く、

「自分と関係ない部分を変更する」これ自体がダメなのである。

まったくもって触っていないコードが壊れることはあり得ない。変更して、1パーセントでも動かなくなる可能性があるなら、それは悪い設計なのである。

思ったよりも多くなってしまたので、次の記事でまた会おう。

Discussion