---
# System prepended metadata

title: ISP　インターフェース分離の原則

---

# ISP　インターフェース分離の原則
**クライアントに、クライアントが利用しないメソッドへの依存を強制してはならない**

## 違反例
さまざまな種類のDoorがある中で、TimedDoorという長時間開け放されていた場合に警報が鳴るドアを考える。
```plantuml
@startuml

Timer -* TimerClient
class TimerClient{
    +TimeOut()
}

TimerClient <|-- Door
Door <|-- TimedDoor

@end
```
これだと、別のDoorを継承したクラスを作成するときに、Timerが必要ではないのにもかかわらずTimerClientを継承しなければならないという不必要な複雑さが生まれてしまっている。

## 解決策1 委譲を使う方法
```plantuml
@startuml
TimerClient *-- Timer
class TimerClient{
    +TimeOut()
}

TimerClient <|-- DoorTimerAdapter
class DoorTimerAdapter{
    +TimeOut()
}

TimedDoor <-- DoorTimerAdapter
Door <|-- TimedDoor

TimedDoor ...> Timer
@end
```
この方法は非常に柔軟だが、ドアが開いてTimeOutを登録するたびに新たなオブジェクトを生成しなければならず、無駄な処理時間やメモリ消費が発生するのでノットエレガントである。　　


## 解決策2 多重継承を使う方法
```plantuml
@startuml
Timer -* TimerClient
class TimerClient{
    +TimeOut()
}
TimerClient <|-- TimedDoor
class TimedDoor{
    +TimeOut()
}
Door <|-- TimedDoor

TimedDoor ..> Timer

@end
```
A202の規約的には禁止
インターフェースの多重継承

# DIP 依存関係逆転の原則
**a.上位のモジュールは下位のモジュールに依存してはならない。どちらのモジュールも「抽象」に依存すべきである。**  
**b.「抽象」は実装の詳細に依存してはならない。実装の詳細が「抽象」に依存すべきである。**

## 違反例 
```plantuml
@startuml
class Button{
    +poll()
}
Lamp <-left- Button

class Lamp{
    +turnOn()
    +turnOff()
}

@end
```
ButtonクラスはLampクラスに直接依存している。
これではButtonクラスがLampクラスの変更の影響を受けてしまうし、Buttonクラスを再利用することもできない。  

## 解決策　内在する抽象を見つける
```plantuml
@startuml
class Button{
    +poll()
}
ButtonServer <-left- Button
ButtonServer <|-- Lamp

class ButtonServer{
    +turnOn()
    +turnOff()
}
@end
```
これなら、ButtonServerインターフェースを実装すれば全てのものに対してButtonから制御することが可能。
Lampは依存される立場からButtonServerに依存する立場になったが、ButtonServerはButtonに依存しているわけではなく、抽象に依存しているだけとなった。