디자인 패턴은 실무에서 사용되는 검증된 해결방법
디자인 패턴을 미리 공부해놓으면 "바퀴를 재발명하는" 상황을 없앨 수 있다. (내가 자주 하는것...)
다만, 디자인 패턴을 남발해서는 안되고 필요한 상황에만 적용하는 것이 좋다.
먼저, DIP를 위반하는 상황 (고수준 컴포넌트가 저수준 컴포넌트에 의존적)에서,우리는 일반적으로 인터페이스를 통해 의존관계를 역전 시킬 수 있다.
그러나 저수준 컴포넌트를 수정할 수 없는 상황(외부 라이브러리) 인 경우, 어댑터 패턴을 활용하면 의존관계를 역전시킬 수 있다.
기존의 방식처럼 인터페이스를 만들되, 해당 인터페이스를 구현하는 Adapter 클래스를 만들어 저수준 컴포넌트의 기능을 감싼다.
Service -> FileStorage 와 같은 구조에서, Service -> Repository(I) <- FileStorageAdapter -> FileStorage 와 같이 의존관계가 역전된다.
복잡한 API 기능들을 하나의 클래스로 묶어 캡슐화하고, 외부에서 편리하게 사용할 수 있도록 하는 패턴
- 여러 클래스에서 반복되는 복잡한 API 호출이 있는 경우
- 순환 참조가 일어나는 경우(두 클래스가 서로를 참조해야 할 때) (중요)
-> 변경의 영향을 서로에게 주는 것은 바람직하지 않다. 따라서 두 클래스가 모두 필요한 기능들을 모아놓은 새로운 클래스를 만들어 순환참조를 없애고, 단일 클래스만 필요한 경우에는 원래대로 사용한다.
와 같은 경우에 대표적으로 사용가능하다.
런타임 중에 전략을 실시간으로 바꿀 수 있도록 하는 패턴
미리 정의되어있는 전략 중, 원하는 것을 클라이언트 코드의 변경 없이 바꿀 수 있다.
추상화와 다형성을 활용한 전략패턴(Repository와 구현체들)이 대표젹인 예시이다.
상속: 자식 클래스가 부모 클래스의 필드와 메서드를 상속받아 사용하는 것
구성: 어떤 클래스가 다른 클래스의 인스턴스를 멤버 변수로 가지는 것
❗️ 메서드 재사용을 위한 상속은 좋지 않다. (캡슐화가 깨지고, 클래스간의 결합이 너무 강해진다)
나의 경험을 돌이켜보면, 강의에서 말하는 바퀴를 재발명하는 상황이 많았던 것 같다. 문제를 어떤식으로 해결할지 몰라 계속 삽질만 하다가, 어찌저찌 해결하고보니 이미 사용되는 패턴이었던 적이 몇 번 있다..ㅎㅎ; 그래서 이번 기회에 언제 어떤 패턴을 사용해야할지 알아놓고 상황에 맞는 패턴을 적용해야겠다는 생각이 들었다. 또, 여러 패턴들이 결국에는 추상화, 캡슐화, 의존관계 역전과 같은 객체지향적인 개념으로부터 파생되었다는 것을 알게되었다.