SOLID原則
S (Single Responsibility) 単一責任の原則
管理者とユーザーの処理を一緒に書いてはいけないという原則です。なぜなら、
・管理者に関するコードだけをいじっているのに、一般ユーザーの機能に影響が出る可能性があると、確認すべき範囲が広がってしまうから。
・管理者、一般ユーザーのコードがごちゃ混ぜになりコードが読みにくくなるから。
「管理者はここ、一般ユーザーはあっち」とすることで機能追加や運用、デバックがしやすくなります。
O (Open-Closed) オープン・クローズドの原則
何か機能を追加するとき、既存のコードを変更するのではなく新しく追加するのが好ましいという原則です。なぜなら、既存のコードの変更は既存の機能のバグを作ってしまう可能性があるから。
例えば,createDrinkメソッドがあります。1種類のフルーツから飲み物を作ります。
def createDrink(fruit)
~
end
ここで、2種類のフルーツから飲み物を作りたくなった場合。
悪い例。既存のコードにfruitをもう一つ足してしまう。
def createDrink(fruit, fruit2)
~
end
良い例。新しく追加することで既存の機能に影響を与えずに済みます。
def createDrink(fruit)
~
end
def createDrinkByTwo(fruit, fruit2)
~
end
L (Liskov Substitution) リスコフの置換原則
子クラスは親クラスと同じメソッドを呼び出せるべき、という原則。
生き物で例えますと生き物クラスは子孫を残すことができます。ならばたんぽぽクラスもカブトムシクラスも人間クラスも子孫を残すことができるべき、と言うことです。逆に子にはあるが親にはないメソッドというのは問題ありません。
I (Interface Segregation) インターフェイス分離の原則
以下が悪い例です。
class Ape
def eat
~
end
def speak
~
end
end
monkey = Ape.new()
human = Ape.new()
humanは話すことはできますがmonkeyは話せません。monkeyインスタンスでspeakを使わなければエラーが出ることはないのですが、初めてApeクラスを扱う人が戸惑ってしまうしわかりづらいのでNGです。
書くことしたら以下のような感じでしょうか
class Ape
def eat
~
end
end
class Monkey < Ape
end
class Human < Ape
def speak
~
end
end
これでmonkeyが喋ることは無くなりました。
D (Dependency Inversion) 依存性逆転の原則
具体は抽象に依存しよう、という原則です。
具体例として、具体の関数が2つあります。
const concrete1 = () => {
number = concrete2()
return number * 10
}
const concrete2 = () => {
return 100
}
こちらの関数、concrete1の中でconcrete2を呼び出しています。このままですとconcrete2に変更を加えたとき、concrete1に影響を出す可能性があります。concrete1がconcrete2に依存している状態です。
ここにインターフェースを加える&concrete2を引数で受け取るようにしてみます。
interface Abstract {
concrete2: () => number
}
const concrete1 = ({concrete2}: {
concrete2: Abstract
}) => {
number = concrete2()
return number * 10
}
const concrete2: Abstract = () => {
return 100
}
すると先程はconcrete1がconcrete2に依存していましたがconcrete1もconcrete2も共にinterfaceに依存しています。このようにすることで、concrete2を変更した際、知らず知らずのうちにconcrete1にバグを生むことは無くなりました。