SOLID 5원칙
SOLID 란
객체지향 개발 5대 원리
시간이 지나도 유지 보수와 확장이 쉬운 시스템을 만들고자 할 때 이 원칙들을 함께 적용할 수 있다.
SOLID 원칙들은 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩터링하여 적용할 수 있는 지침이다.
SRP(Single Resposibility Principle)
정의
작성된 class는 하나의 기능만 가지며 class가 제공하는 모든 서비스는 그 하나의 책임을 수행하는 데 집중되어야 함 → 어떤 클래스를 변경해야 하는 이유는 오직 하나 뿐이어야 한다.
책임 : 변경을 위한 이유
- 특정 기능을 변경하기 위해 여러 클래스가 수정된다면 기본적인 설계 문제 가능성 큼→ 동일한 수정은 한 곳에서 이뤄져야 함 '
- → 클래스가 응집력을 갖지 못했다는 것을 의미
- 특정 기능을 위해서 클래스를 수정하였으나 대부분의 클래스가 수정되지 않았거나, 극히 일부분만 수정되었다면
- → 해당 클래스는 수정된 기능 이외의 여러가지 기능들을 가지고 있다는 의미
ex ) 기능의 문제 → 책임 확인 → 담당 모듈/패키지/함수 확인
SRP는 크고 작은 책임을 적절하게 배치하면 되는 것으로 ,
리팩토링의 해결방법은 직/간접적으로 SRP원리와 관련이 있음.
항상 코드를 최상으로 유지한다는 리팩토링의 개념 → 항상 객체들의 책임을 최상의 상태로 분배한다는 것에서 비롯
적용방법
- 여러 원인에 의한 변경 (Divergent Change)
Extract Class를 통해 혼재된 각 책임을 각각의 개별 클래스로 분할하여 클래스 당 하나의 책임만을 맡도록 하는 것.
책임만 분리하는 것이 아니라 두 클래스 간의 관계의 복잡도(결합도)를 줄이는 것
만약 Extrac Class된 각각의 클래스들이 유사하고 비슷한 책임을 중복해서 가지고 있다면, Extract Supperclass를 사용
Extract Supperclass => Extract된 각각의 클래스들의 공유되는 요소를 부모 클래스로 정의하여 부모클래스에 위임하고 다른 책임들은 각자에게 정의
- 산탄총 수술 (Shortgun surgery)
Move Field 와 Moe Method를 통해 책임을 기존의 어떤 클래스로 모으거나,
모일 클래스가 없다면 새로운 클래스를 정의하여 해결
즉, 응집도를 높이도록 산발적으로 여러 곳에 분포된 책임들을 한 곳에 모으면서 깨끗한 설계
적용이슈
클래스는 자신의 이름이 나타내는 일을 수행해야 함
올바른 클래스 이름은 해당 클래스의 책임을 나타낼 수 있어야 함
각 클래스는 하나의 개념을 나타내야함
사용되지 않는 속성이 결정적 증거
각 객체 간의 응집력이 있다면 병합이 순작용
결합력이 있다면 분리가 순작용
OCP(Open Close principle) 개방폐쇄의 원칙
의미
Open for extension, Closed for modification
클래스 내부 수정 없이 동작을 확장할 수 있어야 한다는 의미
기존의 코트를 수정하지 않고 기능을 추가할 수 있도록 설계되어야 한다.
OCP를 적용하는 방법
- 변하는 것과 변하지 않는 것을 정확하게 구분한다. 변하는 것은(open) 가능한 한 변하기 쉽게 변하지 않는 것은(closed) 변하는 것에 영향받지 않게 설계하는 것이다.
- 두 클래스가 만나는 지점에 인터페이스를 정의한다. 이때, 인터페이스는 변하는 것과 변하지 않는 모듈의 교차점으로 서로를 보호하는 보호막 같은 역할을 한다.
OCP 주의할점
- 확장되는 것과 변경되지 않는 모듈을 분리하는 과정에서 크기 조절을 잘해야 한다. 크기 조절에 실패하면 관계가 더 복잡해져서 설계를 망치는 경우가 있기 때문이다.
- 인터페이스는 가능하면 변경해서는 안 된다.
- 인터페이스 설계에서 적당한 추상화 레벨을 선택하는 것이 중요하다.
LSP(Liskov Substitution Principle)리스코프 치환의 원칙
정의
부모 클래스와 자식 클래스 사이의 행위에는 일관성이 있어야 한다는 원칙이며, 이는 객체지향 프로그래밍에서 부모 클래스의 인스턴스 대신 자식 클래스의 인스턴스를 사용해도 프로그램에 문제가 없어야 한다는 것을 의미한다. 일관성이 있다는 것은 일반화 관계(IS-A)에 있는 것이고, 리스코프 치환 원칙은 일반화 관계에 대해 묻는 것이라 할 수 있다.
ISP (인터페이스 분리의 법칙)
원리
ISP ( Interface Segregation principle ) 원리는
클래스는 자신의 사용하지 않는 인터페이스는 구현하지 말아야 한다는 원리입니다. 즉 클라이언트가 사용하지 않는 메서드에 의존하지 않아야 한다는 뜻입니다.
어떤 클래스가 다른 클래스에 종속될 때에는 가능한 최소한의 인터페이스만을 사용해야 하고 ISP에서는 인터페이스 분리를 통해 변화에서의 적응성을 획득합니다.
정리
쉽게 말하자면 인터페이스를 기능별로 쪼개서 사용하는 인터페이스만 구현해주면 되는 것.
클라이언트를 기준으로 인터페이스를 분리함으로써, 클라이언트로부터 발생하는 인터페이스의 여파가 다른 클라이언트에 미치는 영향을 최소화 한다.
특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
장점
인터페이스를 분리하게 되면 인터페이스가 명확해지고, 대체 가능성 즉 재사용성이 높아진다.
DIP(Dependency Inversion Priciple)
정의
의존 관계를 맺을 때, 변화하기 쉬운것(구체적) 보단 변화하기 어려운 것(추상적)에 의존해야 한다는 원칙
변하기 쉬운 것 ⇒ 구체화 된 클래스
변하기 어려운 것 ⇒ 추상클래스, 인터페이스
구조적 디자인에서 발생하던 하위 레벨의 모듈의 변경이 상위 레벨 모듈의 변경을 요구하는
위계관계를 끊은 의미의 역전
실제 사용 관계는 바뀌지 않으며, 추상을 매개로 메시지를 주고 받음으로써 관계를 최대한 느슨하게 만드는 원칙
상위 클래스일수록, 인터페이스일수록, 추상 클래스일수록 변하지 않을 가능성이 높기에 하위 클래스나 구체 클래스가 아닌 상위클래스, 인터페이스, 추상 클래스를 통해 의존하라는 것
'IOC', '훅 메소드', '확장성' 이 3가지 요소가 조합되어
복잡한 컴포넌트들의 관계를 단순화하고 컴포넌트 간의 커뮤니케이션을 효율적이게 함
IOC
Inversion of Control(제어의 역전)
오브젝트 생성, 관계 설정, 사용, 젝 등 오브젝트 전반에 거친 모든 제어권을 애플리케이션이 갖는게 아니라 프레임워크의 컨테이너에게 넘김
훅 메소드
추상 클래스에 들어있는, 아무 일도 하지 않거나 기본 행동이 정의하는 메소드.
서브 클래스에서 오버라이딩 할 수 있다.
DIP를 만족하는 것은 의존관계를 맺을 때, 구체적인 클래스보다 인터페이스나 추상 클래스와 관계를 맺는다는 것을 의미
적용방법
- Layering
잘 구조화된 객체지향 아키텍처들은 각 레이어마다 잘 정의되고 통제되는 인터페이스를 통한 긴밀한 서비스의 집합을 제공하는 레이어들로 구성되어있다. -Grady Booch
Transitive Dependency(전이 종속성)가 발생했을 때 상위 레벨의 레이어가 하위 레벨의 레이어에 바로 의존하게 되는 것이 아니라 이 둘 사이에 존재하는 추상레벨을 통해 의존해야 함.