객체지향언어와 SOLID원칙
문법을 아는 수준에서 프로그램을 만들다보면 기능은 돌아가게 할 수 있지만 소스는 스파게티가 되곤 한다.
이유는 프로그래밍이 아닌 코딩을 하고 있기 때문이다.
프로그래머는 코더일 수 있지만 코더는 프로그래머가 아니다.
현업에서 일을 하다보면 한번쯤 들을 수 있는 말.
'그 코드 안건드리는게 좋을 거에요.', '그 코드 제가 고칠게요.', '그 소스 만지기 어려울 거에요'
이것은 코드작성의 여러 원칙 중 SOLID원칙을 지키지 않아서일 것이다.
SOLID원칙은 코딩의 종료점이자 설계의 시작점이라고 한다.
SOLID원칙은 다섯가지 원칙이다.
S : Single Responsibility Principle (단일 책임 원칙)
O : Open-Closed Principle (개방 폐쇄 원칙)
L : Liskov Substitution Principle (리스코프 치환 원칙)
I : Interface Segregation Principle (인터페이스 분리 원칙)
D : Dependency Inversion Principle (의존성 역전 원칙)
S : Single Responsibility Principle (단일 책임 원칙)
- 클래스는 단일 책임을 맡는다.
쉽게 말하면 '식당 카운터에서 요리하지 말라'이다.
식당 카운터에서 주문을 했는데 주문담당자가 재료 준비부터, 요리, 주문받기, 계산, 홀 관리 등 모든 것을 다한다면 어떻게 되겠는가?
즉, 하나의 클래스는 하나의 기능만 담당해야 한다.
만약 하나의 클래스에 모든 동작을 집어넣으면 시스템은 비대해지고, 한 부분이 고장나면 전체가 무너진다.
책임이 불분명하면 작은 오류에도 시스템 전체가 움직인다. 원인 파악이 어렵고 유지보수가 오래 걸린다(한마디로 야근해야 한다).
O : Open-Closed Principle (개방 폐쇄 원칙)
- 기존의 코드를 변경하지 않으면서(Closed), 기능을 추가할 수 있도록(Open) 설계가 되어야 한다.
'확장에는 열려있고 수정에는 닫혀있는'이라는 뜻이다.
캐릭터를 하나 생성한다고 할때, 각각의 캐릭터가 움직임이 다를 경우 움직임의 패턴 구현을 하위 클래스에 맡긴다면 캐릭터 클래스의 수정은 필요가 없고(Closed) 움직임의 패턴만 재정의 하면 된다.(Open)
또한 개방 폐쇄 원칙을 수행하기 위해 자주 사용되는 문법이 인터페이스(Interface)이다.
L : Liskov Substitution Principle (리스코프 치환 원칙)
- 자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있다.
부모 클래스와 자식 클래스 사이의 행위에는 일관성이 있어야 한다는 뜻이며, 이는 객체 지향 프로그래밍에서 부모 클래스의 인스턴스 대신 자식 클래스의 인스터스를 사용해도 문제가 없어야 한다는 것을 의미한다.
따라서 자식클래스는 부모 클래스의 책임을 무시하거나 재정의하지 않고 확장만 수행하도록 해야 LSP를 만족한다.
예시) 도형클래스와 그것을 상속받은 OO클래스
(1) 도형은 둘레를 가지고 있다. --> OO은 둘레를 가지고 있다.
(2) 도형은 넓이를 가지고 있다. --> OO은 넓이를 가지고 있다.
(3) 도형은 각을 가지고 있다. --> OO은 각을 가지고 있다.
OO에 사각형을 넣어보자. 그러면 도형클래스를 대체할 수 있다. 하지만 원을 넣으면 3번째 속성을 만족하지 못하기 때문에 도형클래스를 대체할 수 없다. 리스코프 치환 원칙에 위배된다.
I : Interface Segregation Principle (인터페이스 분리 원칙)
- 하나의 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 하나의 일반적인 인터페이스보다 여러개의 구체적인 인터페이스가 낫다.
이는 다시 말해서, 자신이 사용하지 않는 기능(인터페이스)에는 영향을 받지 말아야 한다는 의미이다.
한가지 예를 들어보자. 우리는 스마트폰으로 전화, 웹서핑, 사진 촬영 등 다양한 기능을 사용할 수 있다. 그런데 전화를 할 때에는 웹서핑, 사진촬영 등 다른 기능은 사용하지 않는다. 따라서 전화기능과 웹서핑 기능, 사진 촬영 기능은 각각 독립된 인터페이스로 구현하여, 서로에게 영향을 받지 않도록 설계해야 한다. 이렇게 설계된 소프트웨어는 인터페이스 분리 원칙을 통해 시스템의 내부 의존성을 약화시켜 리팩토링, 수정, 재배포를 쉽게 할 수 있다.
D : Dependency Inversion Principle (의존성 역전 원칙)
- 의존 관계를 맺을 때, 변화하기 쉬운 것보다는 변화하기 어려운 것에 의존해야 한다.
변화하기 쉬운것이란 구체적인 것을 말하고, 변화하기 어려운 것이란 추상적인 것을 말한다. 객체지향적인 관점에서 보자면 변화하기 쉬운것이란 구체화 된 클래스를 의미하고, 변화하기 어려운 것은 추상클래스나 인터페이스를 의미한다. 따라서 DIP를 만족한다는 것은 의존관계를 맺을 때, 구체적인 클래스보다 인터페이스나 추상 클래스와 관계를 맺는다는 것을 의미한다.