4.1.3 리스코프 치환 원칙
LSP -> '기본 클래스의 계약을 파생 클래스가 제대로 치환할 수 있는지 확인하라'라는 말은 파생 클래스가 기본 클래스의 모든 동작을 완전히 대체할 수 있어야 합니다. 파생 클래스가 기본 클래스에 할당된 의도와 계약이 무엇이니를 먼저 파악할 수 있어야 합니다. 원시적으로는 코드 작성자에게 직접 물어보기가 있지만, 명백한 한계가 있기에, 불필요한 커뮤니케이션 비용을 발생시킵니다.
이는 그리 선호하는 방법이 아니고, 세련된 방법으로 테스트 코드를 사용하는 것입니다. 초기 코드 작성자가 생각하는 모든 의도를 테스트 코드로 만들어 두는 것입니다. 그렇게 된다면, 파생 클래스를 작성하는 개발자는 테스트를 보고, 초기 코드 작성자의 의도를 파악할 수 있을 것이고, 기본 클래스로 작성된 테스트에 파생 클래스를 추가해 테스트해 볼 수 있습니다. 인터페이스는 계약이고, 테스트는 계약 명세입니다.
4.1.4 인터페이스 분리 원칙
ISP -> 클라이언트가 자신이 사용하지 않는 인터페이스에 의존하지 않아야 한다는 원칙입니다. 즉, 어떤 클래스가 자신에게 필요하지 않은 인터페이스의 메스드를 구현하거나 의존하지 않아야 한다는 말입니다. 이를 통해 인터페이스의 크기를 작게 유지하고, 클래스가 필요한 기능에만 집중할 수 있습니다.
인터페이스의 정의가 넓어 역할이 모호해지면, 여러 액터들을 상대합니다. 이러한 이유로 인터페이스 분리가 제대로 지켜지지 않은 코드는 SRP 원칙도 위배하고 있을 확률이 높습니다. 인터페이스 분리 원칙이 추구하는 이유는 무엇일까요? 한 가지 강조하자면 '클래스' 분리 원칙이 아닌 '인터페이스' 분리 원칙입니다. 그리고 인터페이스는 곧 역할이라고 부를 수 있다 했는데, 그러므로 ISP 원칙은 역할과 책임을 분리하고, 역할을 세세하게 나누라는 것입니다. 이는 '기능적 응집도'를 추구하는 것이라 볼 수 있고, 응집도를 높이라는 말과 같습니다.
추가로 인터페이스를 분리하는 것이 왜 코드의 재사용성을 높인다는 말일까요? '인터페이스를 이용해 코드의 재사용성을 높인다'라는 말은 '인터페이스 자체'의 재사용성을 높이려는 것이 아닙니다. '인터페이스를 사용하는 코드'의 재사용성을 높이려는 것입니다. 구현에 의존하지 않고, 바뀌지 않는 비즈니스 로직을 여러 곳에서 재사용할 수 있고, 필요에 따라 구현체만 바꾸면 되기 때문입니다.
4.1.5 의존성 역전 원칙
DIP -> 주요 포인트는 3가지로 정리할 수 있습니다. 1) 고수준 모듈은 추상화에 의존해야 한다. 2) 고수준 모듈이 저수준 모듈에 의존해서는 안된다. 3) 저수준 모듈은 추상화를 구현해야 한다. 일단 이는 나중에 보고, 처음부터 의존에 관해 자세하게 알아봅시다.
4.2 의존성
의존은 '다른 객체나 함수를 사용하는 상태'라고 볼 수 있습니다. 사용하기만 해도 의존하는 것이고, 그렇기 때문에 소프트웨어는 의존하는 객체들의 집합이라고 볼 수 있습니다. 컴퓨터공학에서 또 다른 말로 '결합(coupling)'이라는 용어로 사용합니다. 그렇다면 약한 의존 상태는 무슨 의미일까요? 의존성과 결합도를 낮추기 위한 방법으로 의존성 주입(Dependency Injection)입니다.
4.2.1 의존성 주입
의존성 주입은 말 그대로 필요한 의존성을 외부에서 넣어주는(주입)것을 의미합니다. 생성자, 필드, 세터 주입의 방법이 존재하고 자세한 것은 나중에 설명드리겠습니다. 일단 의존성 주입은 의존성 자체를 제거하는 것이 아니라 의존성을 약화시킨다는 것을 명심합시다. 그렇다면 의존성 주입이 어떻게 의존성을 약화시킬까요? 이는 의존 개수를 줄이거나, 불필요한 강한 의존을 생기지 않게 해줍니다.
코드를 작성하며 'new 사용을 최대한 자제하라'라는 말이 있습니다. 왜냐하면 new 사용을 사실 하드 코딩이고 강한 의존성을 만드는 대표적인 사례이기 때문이죠. 무슨말이죠 이건? 어떤 추상 타입의 변수가 하나 있을 때 그 변수에 new를 통해 파생 클래스를 인스턴스화해서 할당한다면 어떨까요? 해당 변수는 추상 타입과 관계없이 고정된 객체를 사용하겠다는 의미가 됩니다. 즉, new 사용시 더 이상 다른 객체가 사용될여지가 사라집니다.
물론 프로그램을 개발하면 new를 사용할 수 밖에 없죠. new 키워드 자체를 부정하는 것이 아니라, 상세한 구현 객체에 의존하는 것을 피하고, 구현 객체가 인스턴스화 되는 시점을 최대한 뒤로 미루라는 뜻 입니다.
4.2.2 의존성 역전
의존성과 의존성 역전의 의미는 다릅니다. Dependency Injection, Dependency Inversion이라서 똑같이 DI로 부를 수 있습니다.
'독서 > 자바,스프링 개발자를 위한 실용주의 프로그래밍' 카테고리의 다른 글
8. 레이어드 아키텍처 (0) | 2024.11.10 |
---|---|
[6-11 중] 6. 안티패턴 (2) | 2024.11.09 |
5. 순환참조 (1) | 2024.11.09 |
2. 객체의 종류 (0) | 2024.11.05 |
[1-5 상] 1. Object-Oriented (0) | 2024.11.05 |