참조
객체지향(obejct-oriented programing)을 왜 사용할까?
객체지향은 실제 무언가를 설계할 때, 우리가 추상적으로 생각하는 설계도라는 개념을 도와줍니다.
즉, 설계적인 측면이 강화된 언어입니다. 절차지향언어보다 (메모리같은)세부적인 설정은 할 수 없지만, 유지보수가 쉽고, 유연하며 확장이 쉬운 애플리케이션을 만들 수 있습니다.
객체지향의 원리
객체지향의 장점을 지키기 위해 따라야하는 5가지 원칙을 SOLID라고 합니다.
5가지 원칙은 서로 조금씩 겹치는 개념(낮은 결합도 높은 응집도, 유지보수 용이 등)이 존재할 수 있습니다.
- Spr(single Responsibility Principle)
- Ocp(Open colse Principle)
- Lsp(The Liskov Substitution Principle)
- Isp(interface Segregation Principle)
- Dip(Dependency Inversion Principle)
1. SPR / 단일 책임의 원칙
어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다.
1.1 정의
SPR원리를 적용하면 책임 영역이 확실해지기 때문에, 한 책임이 변경 될 때 다른 책임들이 변경되야하는 연쇄 작용을 피할 수 있게됩니다.
뿐만 아니라 가독성 향상이라는 이점 까지 누릴 수 있습니다.
1.2 적용방법
- 여러 원인에의한 변경 : extract class를 통해 여러가지 책임이 혼재된 클래스를 개별 클래스로 분할하여 SPR원칙을 지키도록 합니다. 이때 분리된 클래스 간의 복잡도를 줄이도록 설계해야 합니다.
- shotgun surgery : 필드와 메소드를 책임에 맞는 클래스로 모으거나, 새로운 클래스를 만들어 해결합니다. 즉, 여러 곳에 분포된 책임들을 한 곳에 모으면서 응집도를 높이는 작업입니다.
2. OCP / 개방 폐쇄 원칙
소프트웨어 entity(클래스, 모듈, 함수, 컴포넌트)는 확장에 대해서는 열려 있어야 하지만 변경에 대해서는 닫혀 있어야 한다.
2.1 정의
자신의 기존 구성요소를 재활용해서 확장에는 극대화 해야 하고, 주변의 변화 대해서는 기존 구성요소가 영향을 받지 말아야 합니다.
OCP는 재사용 가능한 코드를 만드는 기반이며, OCP를 가능케 하는 중요 메커니즘은 추상화와 다형성 이라고 할 수 있습니다.
2.2 적용방법
- 재사용(변경) 될 것과 변하지 않을 것을 분리합니다.
- 이 두 모듈이 만나는 지점에 인터페이스를 정의합니다.
- 이 인터페이스에 의존하도록 코드를 작성합니다.
2.3 적용 예
대표적으로 JDBC인터페이스가 OCP의 예 입니다. DB를 교체한다 해도 connection 설정만 변경해 주면 됩니다.
3. LSP / 리스코프 치환 원칙
서브 타입은 언제나 자신기반 타입으로 교체할 수 있어야 한다.
3.1 정의
LSP는 규악을 준수하는 상속구조를 제공합니다. 상속은 결국 다형성을 통한 확정성 획득을 목표로 합니다.
하위 클래스의 인스턴스(객체)는 상위형 객체의 참조 변수에 대입해 상위 클래스 역할을 하는데 문제가 없어야 합니다.
일반적으로 상속을 통해 다형성(선언은 기반 클래스로 생성은 구체 클래스로 대입)을 지키고 있다면 이미 LSP를 잘 지키고 있다고 볼 수 있습니다.
3.2 적용방법
- 만약 두 개체가 똑같은 일을 한다면 둘을 하나의 클래스로 표현하고 이들을 구분할 필드를 둡니다.
- 공통된 연산이 없다면 완전 별개인 2개의 클래스로 만듭니다.
- 공통된 연산이 있지만 이들을 각각 다르게 구현한다면 인터페이스 상속을 사용합니다.
- 만약 두 개체가 하는일에 추가적으로 무언가를 구현해야 한다면 extends 상속을 사용합니다.
4. ISP / 인터페이스 분리의 원칙
클라이언트는 자신이 사용하지 않는 메소드에 의존 관계를 맺으면 안 된다.
4.1 정의
SRP처럼 ISP는 각 역할에 맞게 인터페이스로 분리하는 것 입니다. 즉, SRP와 ISP는 같은 문제에 대한 다른 해결책이라고 볼 수 있습니다.
ISP는 한 클래스가 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다는 원칙입니다. 하나의 복합적인 인터페이스 보다는 여러개의 인터페이스가 낫다고 정의할 수 있습니다.
4.2 적용방법
- 클래스 인터페이스를 통한 분리 : 상속을 이용하여 인터페이스를 나눕니다.
- 객체 인터페이스를 통한 분리 : 위임(다른 클래스나 메소드에 맡김)을 이용하여 인터페이스를 나눕니다. 다른 클래스의 기능을 변경없이 사용하고 싶을때 위임을 사용합니다.
4.3 적용사례
Java Swing의 JTable 클래스에는 많은 메소드들이 있습니다. 여러 역할이 하나의 클래스 안에 혼재되어 있지만, JTable입장에서는 모두 제공해야하는 역할입니다.
JTable은 ISP의 원칙대로 인터페이스 분리를 통해 특정 역할만 이용할 수 있도록 해줍니다. 모든 서비스를 필요로 하는 클라이언트 객체에게는 기능 전부를 노출하지만, 특정 서비스에 대해서는 해당 인터페이스를 통해 해당 기능만 노출합니다.
5. DIP / 의존성 역전의 원칙
고차원 모듈은 저차원 모듈에 의존하면 안 된다. 이 두 모듈 모두 다른 추상화 된 것에 의존해야 한다. 추상화 된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화 된 것에 의존해야 한다. 자주 변경되는 구체(구현) 클래스에 의존하지 마라.
5.1 정의
의존 관계의 역전이란 실제 사용 관계는 바뀌지 않으며, 추상을 매개로 메세지를 주고받게해 관계를 느슨하게 만드는 원칙입니다. 이는 구조적 문제에서 발생하던 하위 레벨 모듈의 변경이 상위 레벨 모듈의 변경을 강제하는 위계관계를 끊는 원칙(낮은 결합도)입니다.
DIP는 IoC(제어의 역전), 훅 메소드, 확장성을 조합하여 컴포넌트들의 관계를 단순화하고 컴포넌트 간의 커뮤니케이션을 효율적이게 합니다.
5.2 적용방법
상위 레벨의 레이어가 하위 레벨의 레이어를 바로 의존하는 것이 아니라 이 둘 사이에 존재하는 추상레벨의 레이어를 통해 의존해야 합니다. 이를 통해서 상위레벨의 모듈은 하위레벨의 모듈로의 의존성에서 벗어나 그 자체로 재사용 되고 확장성도 보장 받을 수 있습니다.
잘 구좌화된 객체지향 아키텍처들은 각 레이어마다 잘 통제되는 인터페이스를 통해 긴밀한 서비스들의 집합 된 레이어로 구성되어있습니다.
자신보다 변하기 쉬운 것에 의존하던 것을 추상화된 클래스를 두어 변화에 영향 받지 않게 하는 것이 의존 역전 원칙입니다.
보통 상위 클래스일수록 변하지 않을 가능성이 높기에 하위 클래스나 구체 클래스가 아닌 상위 클래스를 통해 의존하게 하는 것이 의존 역전 원칙입니다.
댓글남기기