SOLID 원칙이란 무엇인가?
SOLID 원칙이란 로버트 마틴이 정리한 좋은 객체 지향 설계의 5가지 원칙을 말한다. 해당 원칙을 지키면 시간이 지나도 변경이 용이하고, 유지보수 및 확장이 용이한 소프트웨어를 개발하는데 도움이 된다고 알려져있다.
- SRP : 단일 책임 원칙 (Single Responsibility Priciple)
- OCP : 개방-폐쇄 원칙 (Open/Closed Principle)
- LSP : 리스코프 치환 원칙 (Liskov Substituion Principle)
- ISP : 인터페이스 분리 원칙 (Interface Segregation Principle)
- DIP : 의존관계 역전 원칙 (Dependency Inversion Principle)
SRP (Single Responsibility Priciple) : 단일 책임 원칙
- 클래스는 단 하나의 책임만 가져야 한다.
- 클래스를 변경하는 이유는 단 하나여야만 한다.
- 중요한 기준은 '변경'으로, 변경이 일어났을 때 해당 변경에 의한 파급효과가 적게해야 한다.
여기서 말하는 클래스는 완전히 캡슐화가 되어있는 상태여야 한다. 또한 SRP에서 의미하는 '책임'이란, 해당 클래스에서의 '기능'으로 생각하면 편하다. 만약 한 클래스에서 동작하는 기능(책임)이 여러개라면 SRP에 위배되는 것이다.
OCP (Open/Closed Principle) : 개방-폐쇄 원칙
- 소프트웨어 요소는 확장에 열려 있으나, 변경에는 닫혀 있어야 한다.
- 기존의 코드를 변경하지 않고 새로운 기능을 추가하거나, 기존의 기능을 수정할 수 있어야 한다.
어떠한 모듈의 기능을 하나 수정할 때, 해당 모듈을 이용하는 다른 모듈들 또한 수정이 필요하다면 유지보수 측면에서 좋지 않다. 만일 위의 OCP 원칙을 적용하여 설계한다면 새로운 모듈을 추가나, 기존의 모듈을 수정 시, 기존의 모듈에서의 코드를 수정하지 않고 추가 및 수정이 가능할 것이다.
위 원칙을 위해서는 추상화(interface)와 상속(다형성)을 통해 구현해야 한다.
LSP (Liskov Substituion Principle) : 리스코프 치환 원칙
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서, 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
즉, 다시 말하면 '상위 타입의 객체'를 '하위 타입의 객체'로 치환해도 정상적으로 동작해야 한다는 의미이다. - 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것, 다형성을 지원하기 위한 원칙, 인터페이스를 구현한 구현체를 믿고 사용하기 위해서는 해당 원칙이 필요하다.
상속관계가 아닌 클래스들을 상속관계로 설정한다면 해당 원칙의 위배가 된다.
ISP (Interface Segregation Principle) : 인터페이스 분리 원칙
- 클라이언트는 자신이 사용하는 메소드에만 의존해야 한다는 원칙
- 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 않아야 한다. 즉, 세부적이고 구체적인 인터페이스를 작성해야 한다.
- 인터페이스는 해당 인터페이스를 사용하는 클라이언트를 기준으로 잘게 분리되어야 한다.
다시 말해, 범용적으로 사용하는 인터페이스 하나보다는 특정 클라이언트를 위한 여러개의 인터페이스로 작성해야 한다는 것이다. 예를 들어, 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스 등 처럼 분리를 해야한다는 원칙이다. 위 처럼 하게되면 인터페이스가 더 명확해지고, 대체 가능성이 높아진다.
DIP (Dependency Inversion Principle) : 의존관계 역전 원칙
- 의존 관계를 맺을 때, 변하기 쉬운 것(구체적인 것)보다는 변하기 어려운 것(추상적인 것)에 의존해야 한다.
- 쉽게 말하면 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻의 원칙이다.
앞에서 이야기한 역할(Role)에 의존하게 해야 한다는 것과 같다. 객체 세상도 클라이언트 가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다. 구현체에 의존하게 되면 변경이 아주 어려워진다.
정리
즉,SRP 와 ISP 는 객체가 커지는 것을 막아준다. 객체가 단일 책임을 갖도록 하고 클라이언트마다 특화된 인터페이스를 구현하게 함으로써 한 기능의 변경이 다른 곳까지 미치는 영향을 최소화하고, 이는 기능 추가 및 변경에 용이하도록 만들어 준다.
LSP 와 DIP 는 OCP 를 서포트한다. OCP 는 자주 변화되는 부분을 추상화하고 다형성을 이용함으로써 기능 확장에는 용이하되 기존 코드의 변화에는 보수적이도록 만들어 준다. 여기서 '변화되는 부분을 추상화'할 수 있도록 도와주는 원칙이 DIP 이고, 다형성 구현을 도와주는 원칙이 LSP 인 것이다.
참고:
https://medium.com/bgl-tech/what-are-the-solid-design-principles-c61feff33685
https://velog.io/@haero_kim/SOLID-%EC%9B%90%EC%B9%99-%EC%96%B4%EB%A0%B5%EC%A7%80-%EC%95%8A%EB%8B%A4
https://mangkyu.tistory.com/194