프로그래밍을 하다 보면 아마 SOLID 객체지향 설계 원칙에 대해
들어본 경험이 있을 겁니다.
프로그램을 개발하는 개발자로서 항상 고민하는 문제는 유지보수성과 성능일 것이다.
객체 지향 5원칙에서는 유지보수성과 관련된 내용을 얘기하고 있다.
SOLID는 객체지향 프로그래밍의 특성과 장점을
최대한으로 끌어올리는 프로그램 설계하도록 도움을 줍니다.
또한 좀 더 유지보수하기 쉽고, 유연하고, 확장이 쉬운 소프트웨어를 만들 수 있습니다.
SOLID에는 5가지 설계 원칙이 존재합니다.
- SRP(Single Reseponsibilty) 단일 책임 원칙
- OCP(Open-Closed) 개방-폐쇄 원칙
- LSP (Liskov Substitution) 리스코프 치환 원칙
- ISP (Interface Sefregation) 인터페이스 분리원칙
- DIP (Dependency Inversion) 의존 역전 원칙
해당 원칙들의 첫 글자를 따서 SOLID 원칙이라고 부릅니다.
SRP (Single Responsibility) 단일 책임 원칙

- 클래스는 단 하나의 책임을 가져야 한다.
- 클래스가 변경되는 이유는 단 하나여야 한다.
- 클래스가 제공하는 모든 서비스는 그 하나의 책임을 수행하는데 집중되어 있어야 한다.
모든 클래스는 각각 하나의 책임만을 가져야 한다는 것이고,
변경되는 이유가 단 하나여야 한다는 것은
말이 조금 어렵지만
클래스 하나에 이것저것 다 넣으면 단일 책임 원칙을 어길 가능성이 높아진다는 것입니다.
그렇다면,
책임의 기준은 무엇이고, 클래스엔 얼마나 어떻게 넣어야 할까?
처음에 설명에서 이야기했듯이 객체 지향 원칙에서는
유지보수성에 대해 논하는 것입니다.
따라서 제가 생각하기에는 정확이 얼마나 객체를 어떻게 나눠라
라는 이야기보다는 기능으로 나누든 목적으로 나누든
최종적으로는 유지보수성이 극대화되도록 설계하라는 것에 더 가깝다고 생각합니다.
따라서 결론적으로 SRP란
유지보수성이 높고, 연쇄 책임이 일어나지 않도록 객체에게 너무 많은 책임을 주지 않는 것을 말합니다.
OCP (Open-Closed) 개방-폐쇄 원칙

- 확장에는 열려있어야 하고, 변경에는 닫혀있어야 합니다.
요구사항의 변경이나 추가 사항이 발생하더라도, 기존 구성요소는 수정이 일어나지 말아야 하며,
기존 구성요소를 쉽게 확장해서 재사용할 수 있어야 합니다.
열린 확장에서는
추가사항이 발생하더라도 기존의 요소를 수정하지 않아도 됨을 의미하고,
닫힌 변경에서는
요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소를 수정이 없어야 함을 의미합니다.
만약 게임 캐릭터를 만든다고 하였을 때
모든 캐릭터는 모션이 있지만 모두 다른 모션을 할 때,
모션을 가진 캐릭터를 만들고 자세한 모션 구현은 하위 클래스에 맡긴다면
캐릭터 클래스의 수정은 필요 없고, 움직임만 재정의하여 구현할 수 있습니다.
OCP는 추상화(인터페이스)와 상속(다형성) 등을 통해 구현해 낼 수 있습니다.
자주 변화하는 부분을 추상화함으로써 기존의 코드를 수정하지 않고, 기능을 확장할 수 있도록
유연함을 높이는 것이 중요합니다.
LSP (Liskov Substitution Principle) 리스코프 치환 원칙

- 하위 타입 객체를 상위 타입에서 가능한 행위를 수행할 수 있어야 함
- 상속관계에서는 꼭 일반화 관계(IS-A)가 성립해야 합니다.
즉 자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있다는 원칙입니다.
예를 들자면 직사각형을 부모라고 하고 정사각형을 자식이라 하여 예시를 들자면
직사각형은
- 네 내각의 크기는 모두 직각이다. O
- 두 쌍의 대변의 길이가 각각 같다. O
- 두 쌍의 대각선의 크기가 각각 같다. O
- 대각선은 서로 다른 대각선을 이등분한다. O
이를 정사각형에 대입해 보면
- 네 내각의 크기는 모두 직각이다. O
- 두 쌍의 대변의 길이가 각각 같다. O
- 두 쌍의 대각선의 크기가 각각 같다. O
- 대각선은 서로 다른 대각선을 이등분한다. O
로 모두 성립하고 부모 클래스를 대체할 수 있습니다.
이런 경우에는 성립한다고 할 수 있습니다.
하지만 이를 원에 대입하면
- 네 내각의 크기는 모두 직각이다.?
- 두 쌍의 대변의 길이가 각각 같다.?
- 두 쌍의 대각선의 크기가 각각 같다.?
- 대각선은 서로 다른 대각선을 이등분한다.?
과 같은 이상한 결과가 나오게 된다.
이런 경우에는 LSP에 위배된다고 할 수 있습니다.
ISP (Interface Segregation Principle) 인터페이스 분리 원칙

- 클라이언트는 자신이 사용하는 메서드에만 의존해야 한다.
- 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 않아야 합니다.
클래스가 서로 관계없는 기능을 가지고 있다면 굳이 필요 없는 곳에 작업하는 것에 대한 낭비가 되고,
예상치 못한 버그를 발생시킬 수 있습니다.
하나의 통상적인 인터페이스보단 여러 개의 구체적인 인터페이스가 낫습니다.
DIP (Dependency Inversion Principle) 의존성 역전 원칙

- 의존 관계를 맺을 때에는 변하기 쉬운 것보다는 변하기 어려운 것에 의존해야 합니다.
즉, 의존 관계를 맺을 때는 구체화된 클래스보다는 추상 클래스나 인터페이스에 의존해야 한다는 것입니다.
변경됨에 따라 모든 것이 변경되어야 하는 결합도가 높은 관계가 아닌
객체 간의 관계가 느슨하게 확장성이 용이하도록 다움을 주는 것입니다.
요약
객체지향 설계 원칙은
각 객체의 크기가 너무 커지는 것을 막아주고,
변경에 따라서 다른 곳에 미치는 영향을 최소화하고, 기능 추가 및 변경에 용이하게 하여
소프트웨어가 더욱 확장성이 용이하고,
유연한 프로그램을 만들어, 유지보수가 용이한 프로그램을 만들 수 있도록 도와주는 것입니다.
'Programming' 카테고리의 다른 글
프로그래밍의 메모리 영역 (0) | 2022.12.04 |
---|