티스토리 뷰

개발/이론

[객체지향] SOLID 원칙

는세 2018. 12. 18. 17:32
반응형

SOLID 란?

 : 객체지향에서 꼭 지켜야 할 5개의 원칙을 말합니다. 5원칙 각각의 이니셜을 따서 SOLID 라고 부릅니다.  

좋은 객체지향 설계를 위해서는 SOLID 원칙을 따르는 것이 좋습니다.

 물론 어떤 이론이나 원리를 현실에서 딱 맞게 적용하는 것은 어렵지만, 기본 원리를 숙지한 후에 적용하려고 노력하는 것과 아예 모르는 상태로 구현하는 것과는 많은 차이가 있을 것입니다. 또한  이 원칙들을 기반으로 디자인 패턴을 공부한다면 왜 이 패턴을 사용하고 유명한 지 알기 쉽습니다. 



1. S  - SRP 

 :  Single Responsibility Principle - 단일 책임의 원칙

THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.

하나의 클래스(객체)는 오직 하나의 책임을 가진다.

= 그 클래스를 수정해야 할 이유는 오직 하나임


- 예를 들어, 계산을 담당하는 calculation 클래스가 있다. 이 클래스는 자신의 역할인 '계산' 기능만을 책임져야 한다. 그러므로 만약 계산 방법에 문제가 생기거나, 새로운 연산을 추가하거나 기존 연산을 삭제해야 할 때만 수정을 해야한다.

- 만약에 해당 클래스를 이용하여, 실제 계산기 어플리케이션을 만든다고 가정할 때, Caculation 클래스 내부에, GUI 부분까지 같이 구현이 된다면 SRP 원칙에 위배된다.



2.  O -  OCP

: Open Close Principle - 개방/폐쇄의 원칙

YOU SHOULD BE ABLE TO EXTEND A CLASSES BEHAVIOR, WITHOUT MODIFYING IT.

확장에 대해서는 개방 되어 있어야 하지만, 수정에 대해서는 폐쇄 되어야 한다.

 = 객체 기능의 확장 허용, 스스로 변경은 피함


- 예를 들어 RPG 게임을 만들 때, Character 들은 기본적으로 '기본 공격' 스킬을 가지고 있어야 한다. 

그런데 캐릭터의 직업에 따라서 기본 공격 스킬은 형태가 달라진다, 마법사는 '마법', 전사는 '때리기'., 궁수는 '활쏘기' 형태의 공격을 해야 한다. 

- 이런 경우에, 공격의 구체적인 내용을 하위 클래스에서 구현한다면, Character 클래스 자체의 수정은 필요가 없으며, 공격 '방법'에 대해서만 각 캐릭터에서 구현해주면 된다.

-> 수정에 대해서는 폐쇄적, 확장에 대해서는 개방


- 구현 방법

(1) 변경(확장)될 것과 변하지 않을 것을 엄격히 구분

(2.) 두 모듈이 만나는 지점에 인터페이스를 정의

(3) 정의한 인터페이스에 의존하도록 코드를 작성



3. L - LSP

 : Liskov Substitusion Principle - 리스코프 치환 법칙

FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT.

서브 타입은 언제나 기반 타입(Base Type)으로 교체할 수 있어야 한다.  

= 자식 클래스는 언제나 자신의 부모클래스를 교체할 수 있다는 원칙 

(즉 부모클래스가 들어갈 자리에 자식 클래스를 넣어도 계획대로 잘 작동해야 한다는것.)


- 인터페이스 :  구현 클래스는 인터페이스를 지켜야 함 

- 클래스 :  하위 클래스는 상위 클래스의 한 종류여야 함  (두 경우 모두 컴파일 에러로서 막히는 곳이 많음)

- 리스코프 원칙

(1) 하위형에서 선행조건은 강화될 수 없다.

(2) 하위형에서 후행조건은 약화될 수 없다.

(3) 하위형에서 상위형의 불변조건은 반드시 유지되어야 한다.



4. I - ISP

 : Interfa Interface Segregation Principle - 인터페이스 분리 원칙

NO CLIENT SHOULD BE FORCED TO DEPEND ON METHODS IT DOES NOT USE. 

(=CLIENTS SHOULD NOT BE FORCED TO DEPEND ON INTERFACES THAT THEY DO NOT USE.)

한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 하나의 일반적인 인터페이스보다는 여러 개로 쪼개진 구체적인 인터페이스가 낫다.

클라이언트가 자신이 이용하지 않는 메소드에 의존하지 않아야 한다는 원칙


- 자신이 사용하지 않는 기능(인터페이스)에는 영향을 받지 말아야 함

SRP가 클래스의 단일책임을 강조한다면, ISP는 인터페이스의 단일책임을 강조

- EX ) 같은 클라이언트라도, 기능에 따라서 더 구체적으로 나눌 수 있다. => 충돌강조기능과 이펙트강조기능 등 세부적으로

적용 이슈

(1) 기존에 구현된 클라이언트에 변경을 주지 말아야 함

(2) 두 개 이상의 인터페이스가 공유하는 부분의 재사용을 극대화

(3) 서로 다른 성격의 인터페이스를 명백히 분리



5. D - DIP

 : Dependency Inversion Principle - 의존성 역전 법칙

A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS.

B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS.

잘 설계된 객체-지향 프로그램의 의존 구조는 전통적 절차적 메소드의 결과로 만들어지는 의존 구조를 "역전"(invert)한 형태


고차원의 모듈은 저차원의 모듈에 의존하면 안된다. 이 두 모듈 모두 다른 추상화된 것에 의존 해야 함 

- 추상화 된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화된 것에 의존해야 함




안 좋은 프로그래밍 법칙

1. 모든 변경마다 많은 다른 부분에 영향을 미쳐 변경 자체가 어렵다. (Rigidity)

2. 변경 작업을 할때 예상치 못한 다른 부분이 망가진다. (Fragility)

3. 현재의 어플리케이션에서 분리할 수 없기 때문에 다른 어플리케이션에서 재사용 하기가 매우 어렵다. 

(Immobility)


참고

http://wonwoo.ml/index.php/post/1717


반응형
댓글