객체지향원칙

seonja kim·2020년 7월 11일
1

의미

객체지향 디자인 원리들을 사용하면 좀 더 유지보수가 쉽고 유연하고 확장이 쉬운 소프트웨어를 만들 수 있다.

객체지향이 나온 이유 :

객체지향 전의 코드는
A,B,C가 있다고 가정하자. 각각 창문 닦기, 바닥 쓸기, 물걸레질하기를 시킨다고 가정할 때

A에게 창문 닦기를 배정하고 무슨 용품을 사용하여 어디를 청소해야 하는지 지정해주고, 걸레가 더러워졌을 경우 등 각각의 상황변화에 대해 또 다른 지시를 내려야 한다.

같은 업무를 D,E와 같은 새로운 사람에게 시킬 경우, 같은 지시를 무한반복하게 되는 비효율이 생기게 된다.


이를 공통된 활동에 따라 정리(객체화)하여 반복을 줄이고 사용 / 유지 / 보수를 쉽게 한 것이 객체지향이다.


5가지 원리의 핵심내용

SRP 단일책임의 원칙 (Single Responsibility Principle)

작성된 클래스는 하나의 기능만을 가지며 클래스가 제공하는 모든 서비스는 그 하나의 책임을 수행하는 데 집중되어 있어야 한다. 책임 영역이 확실해지기 때문에 연쇄작용에서 자유로울 수 있다. 코드의 가독성 향상, 유지보수 용이라는 이점을 누릴 수 있다.


OCP 개방폐쇄의 원칙 (Open Close Principle)

소프트웨어의 구성요소 (컴포넌트, 클래스, 모듈, 함수)는 확장에는 열려있고 변경에는 닫혀있어야 한다는 원리이다. (변경을 위한 비용은 줄이고 확장을 위한 비용은 가능한 극대화)

요구사항의 변경이나 추가사항이 발생하더라도 기존 구성요서는 수정이 일어나지 않아야 하며 기존 구성요소를 확장해서 재사용할 수 있어야 한다.

추상화된 인터페이스를 선언한 후 그 인터페이스를 상속받아 구체적인 행위를 구현

  • 장점 : 경직성이 줄어들고 빠르고 안정적인 수정을 가능하게 함

  • 단점 : OCP가 남용되면 불필요한 복잡성을 띄게 됨


고민해야 할 부분 :

어떤 부분을 추상화하고 어떤 부분을 구체화할 것인지 판단하기 어려우므로 단순하게 변경이 없음을 가정하고 개발하는 것이 유리하다.

적용방법 :

OCP는 연습없이 적용하기가 어렵다고 한다. 평소에 if / switch 구문을 제한하는 코드를 짜면서 연습하는 것을 추천


LSP 리스코브 치환의 원칙 (The Liskov Substitution Principle)

참고자료 : [Swift OOP] LSP (리스코프치환원칙)

OCP를 가능하게 해주는 원칙이다.

예시를 사용한 설명 :

<직사각형과 정사각형>
=> 일반적으로 정사각형은 직사각형의 한 부분이므로 직사각형의 자식으로 정사각형을 놓을 수 있다고 생각하기 쉽지만 둘은 상속관계를 가지면 안된다.

  • 이유 :
    직사각형에 width를 정하는 setWidth라는 함수가 있다고 가정
    정사각형의 width와 height는 연관되어 있으므로 setWidth에 변경이 있을 경우 height에도 변경이 있게 되고 이는 부모의 법칙을 깨버리게 된다.

    <동물과 활동>
    동물이라는 class에 걷기와 뛰기가 있다고 가정할 경우, 걷기와 뛰기는 개와 고양이 같은 동물에게는 적용될 수 있지만 고래와 같은 어류에게는 적용이 불가능하므로 걷기, 뛰기, 헤엄치기 등의 행위는 상속과 별도로 존재해야 한다.

상속할 때 해서는 안되는 행위 :

  • 부모의 행위를 자식이 거부
  • 퇴화함수 : 슈퍼클래스에 있는 특정 메소드들을 오버라이트하여 그 기능을 못 쓰게 하는 것

현실 :

모든 코드에서 LSP를 지키기는 어렵기에 적정선에서 타협해야 한다. 하지만 이를 이해하고 있다는 것으로 설계에 도움을 받을 수 있고 미래에 발생할 수 있는 문제를 사전 예방할 수 있다.

복잡하고 이해할 수 없는 상속은 만들지 않도록 한다.


ISP 인터페이스 분리의 원칙 (Interface Segregation Principle)

interface : Two or more separated components of a computer system exchange information.

인터페이스를 명확한 목적별로 잘게 나누고 인터페이스 기준으로 코딩을 한다.

서버(사용되는 쪽)는 클라이언트(사용하는 쪽)가 필요로 하는 최소한의 인터페이스만 제공해서 둘 간의 의존도를 낮추어야 한다.


어떤 클래스가 다른 클래스에 종속될 때에는 가능한 최소한의 인터페이스만을 사용해야 한다. SRP가 클래스의 단일책임을 강조한다면 ISP는 인터페이스의 단일책임을 강조한다.


DIP 의존성역전의 원칙 (Dependency Inversion Principle)

참고자료 :
[Swift OOP] DIP (의존관계역전원칙) #1
[Swift OOP] DIP (의존관계역전원칙) #2


구조적 디자인에서 발생하던 하위 레벨 모듈의 변경이 상위 레벨 모듈의 변경을 요구하는 위계관계를 끊는 의미의 역전이다.


의존관계는 단방향으로 흘러가는 것이 좋다.

하지만 아래의 그림과 같이 Class C가 Class A 또는 Class B에 의존해야 하는 상황이 발생할 경우 DIP가 해결책이 된다.


복잡한 컴포넌트간의 커뮤니케이션 관계를 단순화하기 위한 원칙이다.


의존 관계의 방향 :

  • 구체적 => 추상적
    추상적인 것이 구체적인 것에 의존하지 않아야 함
    상위수준(추상적인 부분)은 하위수준(구체적인 부분)에 의존하면 안됨

  • 추상적인 부분 (정책) : 자주 변경되지 않는 부분 / 로직의 뼈대

  • 구체적인 부분 (세부) : 자주 변경되는 부분 / 자꾸 추가되는 부분


예시를 이용한 이해 :

<램프와 버튼의 관계>

  • 버튼이 램프를 가지고 있을 경우 이 버튼은 램프에만 사용할 수 있다.

  • 버튼이 인터페이스를 제공하고 그것을 통해 램프를 제어하는 것이 DIP이고 이 버튼은 다양항 디바이스에 사용이 가능하게 된다.

  • 모든 상속관계를 끊는 방법 : switchableDevice라는 소유권이 없는 인터페이스를 사용하여 버튼과 램프는 이 인터페이스에만 의존성을 가지게 된다.
profile
Adventurer

0개의 댓글