Solid 5원칙은 소프트웨어 개발에서 가이드라인으로 사용되는 원칙으로, 소프트웨어의 품질을 높이고 유지보수를 용이하게 하기 위해 만들어졌습니다. 이 5가지 원칙은 다음과 같습니다.
1. SRP (Single Responsibility Principle)
한 클래스는 하나의 역할만 수행
- 특징
- 한 책임의 변경에서 다른 책임의 변경으로의 연쇄작용에서 자유로울 수 있습니다.
- 코드의 가독성 향상, 유지보수 용이
- 다른 원리들을 적용하는 기초가 됩니다.
- 실무의 프로세스는 매우 복잡 다양하고 변경 또한 빈번하기 때문에 경험이 많지 않거나 도메인에 대한 업무 이해가 부족하면 나도 모르게 SRP원리에서 멀어져 버리게 됩니다. 따라서 평소에 많은 연습(‘책임’이란 단어를 상기하는)과 경험이 필요한 원칙입니다.
- 적용방법
- 여러 원인에 의한 변경 (Divergent change): Extract Class를 통해 혼재된 각 책임을 각각의 개별 클래스로 분할하여 클래스 당 하나의 책임만을 맡도록 하는 것입니다.
- 산탄총 수술(Shotgun surgery): Move Field와 Move Method를 통해 책임을 기존의 어떤 클래스로 모으거나, 이럴만한 클래스가 없다면 새로운 클래스를 만들어 해결할 수 있습니다.
- 예시 코드
2. OCP (Open-Closed Principle) :
확장에는 열려 있고 변경에는 닫혀 있어야 한다.
- 특징
- 변경을 위한 비용은 가능한 줄이고 확장을 위한 비용은 가능한 극대화 해야 한다는 의미
- 요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소는 수정이 일어나지 말아야 하며, 기존 구성요소를 쉽게 확장해서 재사용할 수 있어야 한다
- 관리가능하고 재사용 가능한 코드를 만드는 것이 기반이며, 가능케 하는 중요 메커니즘은 추상화와 다형성
- 객체지향의 장점을 극대화
- 적용방법
- 변경될 것과 되지 않을 것을 분리한 후, 두 모듈이 만나는 지점에 인터페이스를 정의
- 인터페이스에 의존하도록 코드 작성
- 예시 코드
만약 기타 뿐만 아니라 다른 악기도 관리해야 한다면?
* 인터페이스는 가능하면 변경되면 안 됩니다. 따라서 인터페이스를 설계할 때 어느 정도의 예측능력을 요합니다.
3. LSP (Liskov Substitution Principle)
서브 타입은 언제나 자신의 기반 타입으로 교체할 수 있어야 한다. (상당히 어려운 내용... 이해를 잘 못했음)
- 특징
- 서브 타입은 언제나 기반 타입으로 교체할 수 있어야 한다. 달리 말하면 서브 타입은 기반 타입이 약속한 규약(public 인터페이스)을 지켜야 합니다.
- 서브 클래스가 확장에 대한 인터페이스를 준수해야 함을 의미합니다.
- 다형성과 확장성을 극대화하려면 하위 클래스를 사용하는 것보다는 상위의 클래스(인터페이스)를 사용하는 것이 더 좋습니다. 일반적으로 선언은 기반 클래스로 생성은 구체 클래스로 대입하는 방법을 사용합니다. 생성 시점에서 구체 클래스를 노출시키기 꺼려질 경우 생성 부분을 Abstract Factory 등의 패턴을 사용하여 유연성을 높일 수 있습니다. 상속을 통한 재사용은 기반 클래스와 서브 클래스 사이에 IS-A관계가 있을 경우로만 제한되어야 합니다. 그 외의 경우에는 합성(composition)을 이용한 재사용을 해야 합니다. 상속은 다형성과 따로 생각할 수 없습니다. 그리고 다형성으로 인한 확장 효과를 얻기 위해서는 서브 클래스가 기반 클래스와 클라이언트 간의 규약(인터페이스)을 어겨서는 안 됩니다. 결국 이 구조는 다형성을 통한 확장의 원리인 OCP를 제공하게 됩니다. 따라서 LSP는 OCP를 구성하는 구조가 됩니다. 객체지향 설계 원리는 이렇게 서로가 서로를 이용하기도 하고 포함하기도 하는 특징이 있습니다. LSP는 규약을 준수하는 상속구조를 제공합니다. LSP를 바탕으로 OCP는 확장하는 부분에 다형성을 제공해 변화에 열려있는 프로그램을 만들 수 있도록 합니다. (nextree 글 중 일부인데 이해가 잘 안감)
- 쉬운 예시 - 자동차 인터페이스의 엑셀은 앞으로 가는 기능, 뒤로 가게 구현하면 LSP 위반, 느리더라도 앞으로 가야 함
* 다형성을 위한 상속 관계가 필요 없다면 Replace with Delegation을 합니다. 상속은 깨지기 쉬운 기반 클래스 등을 지니고 있으므로 IS-A관계가 성립되지 않습니다. LSP를 지키기 어렵다면 상속대신 합성(composition)을 사용하는 것이 좋습니다.
4. ISP (Interface Segregation Principle)
클라이언트는 자신이 사용하지 않는 인터페이스에 의존하도록 강요받아서는 안된다.
- 특징
- 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 합니다. 즉 어떤 클래스가 다른 클래스에 종속될 때에는 가능한 최소한의 인터페이스만을 사용해야 합니다.
- ISP를 ‘하나의 일반적인 인터페이스보다는, 여러 개의 구체적인 인터페이스가 낫다’라고 정의할 수 도 있습니다.
- SRP가 클래스의 단일책임을 강조한다면 ISP는 인터페이스의 단일책임을 강조합니다.
- 쉬운 예시 - 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스
- 적용방법
- 클래스 인터페이스를 통한 분리
- 객체 인터페이스를 통한 분리
* 기 구현된 클라이언트에 변경을 주지 말아야 하며 서로 다른 성격의 인터페이스를 분리해야 합니다.
5. DIP (Dependency Inversion Principle)
추상화에 의존해야지 구체화에 의존하면 안 된다.
- 특징
- 구조적 디자인에서 발생하던 하위 레벨 모듈의 변경이 상위 레벨 모듈의 변경을 요구하는 위계관계를 끊는 의미의 역전입니다. 실제 사용 관계는 바뀌지 않으며, 추상을 매개로 메시지를 주고받음으로써 관계를 최대한 느슨하게 만드는 원칙입니다.
- DIP의 키워드는 ‘IOC’, ‘훅 메서드’’, ‘확장성’입니다. 이 세 가지 요소가 조합되어 복잡한 컴포넌트들의 관계를 단순화하고 컴포넌트 간의 커뮤니케이션을 효율적이게 합니다.
- 적용 방법
- layering
# reference
chatgpt
'Back-end > Spring 기초개념' 카테고리의 다른 글
Instagram-clone 분석 (3) DTO (0) | 2023.04.23 |
---|---|
Instagram-clone 분석 (2) entity (3) | 2023.04.22 |
Instagram-clone 분석 (1) (2) | 2023.04.19 |
@Bean과 @Component (2) | 2023.03.29 |
[JAVA] 내부 클래스, 내부 static 클래스의 역할 (0) | 2023.03.10 |