🐈
"いい"コードとは 3(SOLIDの原則 I 編)
前回の記事を見ていない人は、
から見てくれると助かる。
Interface Segregation Principle (インターフェース分離の原則)
結論から言うと、
「抽象クラスやインターフェース継承先で使わないメソッドがないようにわけよう」
ということ。
つまるところ、余計な結合をなくしましょうということである。
具体例
毎度のとおり、犬猫でたとえてみよう。
//動物の行動
interface AnimalTasks {
walk(): void;
fly(): void;
swim(): void;
}
このようなanimalの行動がまとめられていたインターフェースがあるとする。
こいつを継承するサブクラスが、以下のとおりとする。
//🐶Dogの実装
class Dog implements AnimalTasks {
walk() {
console.log("てくてく歩くわん");
}
fly() {
throw new Error("ぼく飛べませんけど!?💢");
}
swim() {
console.log("頑張って泳ぐわん");
}
}
//🐱Catの実装
class Cat implements AnimalTasks {
walk() {
console.log("にゃ〜ん、のそのそ");
}
fly() {
throw new Error("飛ばないよ!にゃんこよ!?");
}
swim() {
throw new Error("泳げないの!水キライなの!");
}
}
// 🐦Birdの実装
class Bird implements AnimalTasks {
walk() {
console.log("ちょこちょこ歩くちゅん🐦");
}
fly() {
console.log("ばさばさ飛ぶちゅん✨");
}
swim() {
throw new Error("水に浮かないよ!ばちゃばちゃ!");
}
}
全ての行動持ったインターフェースを継承してしまうと、本来空を飛べないdogが、「飛ぶ」といったり、猫が「泳ぐ」といったような振る舞いを獲得してしまう。
こうなってしまうと、サブクラスで本来あり得ない行動をとることができ、バグの原因につながる。
ではどうすればいい?
インターフェースを細かく分け、それぞれの振る舞いに対してのみ、適用する。
行動はそれぞれインターフェースを分けて置き、それぞれのクラスに個別に継承する。
interface Walkable {
walk(): void;
}
interface Swimmable {
swim(): void;
}
interface Flyable {
fly(): void;
}
class Dog implements Walkable, Swimmable {
walk() {
console.log("てくてく歩くわん🐾");
}
swim() {
console.log("ちゃぷちゃぷ泳ぐわん💦");
}
}
class Cat implements Walkable {
walk() {
console.log("のそのそ歩くにゃん🐾");
}
}
class Bird implements Walkable, Flyable {
walk() {
console.log("ちょこちょこ歩くちゅん🐤");
}
fly() {
console.log("ばさばさ飛ぶちゅん✨");
}
}
これにより、依存関係を最小に抑えることができ、変更に強く、理解しやすい設計になる。
結論
抽象クラスやインターフェース継承先で使わないメソッドがないように分けることで、保守性が高い設計になる。
インターフェースを細かく分類し、依存関係を減らすことで、リスクを減らしていこう。
Discussion