어떤 클래스를 변경해야 하는 이유는 오직 하나 뿐이어야 한다.
class Animal{
val kind : String
fun 짖다(){
when(kind){
"강아지" -> print("멍멍")
"고양이" -> print("야옹")
else
...
}
}
}
Animal 클래스에서 짖다 메서드를 모든 동물에 대해 구현하려고 하여 SRP를 위반하고 있다.
abstract class Animal{
abstract fun 짖다()
}
class Dog : Animal(){
override fun 짖다() = print("멍멍")
}
class Cat : Animal(){
override fun 짖다() = print("야옹")
}
위의 코드처럼 Animal이라는 추상 클래스를 두고, 상속을 받아 Dog와 Cat에 맞게 짖다 메서드를 구현하여 SRP를 지킬 수 있다.
클래스, 모듈, 함수 등 소프트웨어 구성요소는 확장에 대해 열려있어야 하고 변경에 대해서는 닫혀 있어야 한다.
이는 변경을 위한 비용은 가능한 줄이고, 확장을 위한 비용은 가능한 극대화 해야 한다는 의미이다. Interface 구현을 통해 이를 해결한다.
FileStorage에서 Oracle, MySQL 말고 새로운 파일을 저장해야 할 때, save_to_XXX() 라는 메서드를 추가하여 기존의 코드를 변경하게 되어 OCP를 지키지 못하게 된다.
FileStorage 인터페이스를 만들어 save() 추상 메서드를 선언한다. 새로운 파일을 저장해야 하더라도 FileStorage를 구현하여 save()를 작성하면 되므로 기존 코드의 변경 없이 확장이 가능하다.
서브 타입은 언제나 자신의 기반 타입으로 교체 할 수 있어야 한다.
하위 클래스의 인스턴스를 상위형 객체 참조변수에 대입해 상위 클래스의 인스턴스 역할을 수행하는데 문제가 없어야 한다.
박쥐는 표유류이고 동물이기도 하므로 동물 animal = new 박쥐() 가 성립되어 LSP가 지켜진다. 하지만 딸이 할아버지가 될 수는 없으므로 LSP가 지켜지지 않는다.
ISP는 SRP와 비슷하지만 인터페이스를 통한 다른 해결책을 제안하고 있다. 일반적으론 ISP보다 SRP 할 것이 권장된다.
EX) 큰 카테고리로 분류가 되면 ISP로 적용 하는것이 유리. SRP를 우선적으로 적용 하기로 약속한다.
고차원 모듈은 저차원 모듈에 의존하면 안된다. 추상화된 것은 구체적인 것에 의존하면 안된다. 구체적인 것이 추상화 된 것에 의존해야 한다. 자주 변경되는 클래스에 의존하지 말자. 로 요약될 수 있다. 즉, 자신보다 변하기 쉬운 것에 의존하지 말라는 것이다. 해결방법은 OCP와 비슷한데, 구체적인 class가 아닌, 인터페이스에 의존함으로써 DIP를 해결한다.
출처: https://sjh836.tistory.com/159
https://velog.io/@lsb156/객체지향-개발-5대-원칙-SOLID
https://blog.naver.com/jenny25697/222664023806
https://yoongrammer.tistory.com/97
저는 누구한테 의존해야하나요?