프로필사진

IT Anthology/encyclopedia

[객체 지향 프로그래밍] SOLID 원칙

다각 2022. 3. 18. 07:48

* 이 글은 코드잇의 <객체 지향 프로그래밍> 코스를 수강하고 정리한 글입니다.
* 나중에라도 제가 참고하기 위해 정리해 두었으며, 모든 내용을 적은 것이 아닌,
필요하다고 생각되는 부분만 추려서 정리한 것임을 미리 밝힙니다.


SOLID 원칙을 지키면 유연하고 유지보수하기 쉬운 견고한 코들르 쓸 수 있다고 한다.

프로그램의 크기가 커질 수록 SOLID 원칙을 잘 지키는 것이 중요하다.

하지만 작고 간단한 프로그램을 만드는데 이 원칙을 지키면 오히려 시간 낭비가 될 수도 있다.

SOLID 원칙에는 아래 다섯가지가 있다.

 

1. 단일 책임 원칙 (Single Responsibility Principle)

: 모든 클래스는 단 한가지의 책임만을 갖고, 클래스 안에 정의되어 있는 모든 기능은 이 하나의 책임을 수행하는데 집중되어 있어야 한다.

: 여기서 한 가지 책임이 어디서부터 어디까지인지 모호함...

: SOLID 원칙의 창시자 Robert C.Martin 왈, "단일 책임 원칙은 같이 수정해야될 것들은 묶고, 따로 수정해야될 것들은 분리하는 것" 이라고 한다.

: 즉, 나중에 기능을 수정해야할 때 그 책임을 지는 클래스만 수정할 수 있도록

: God object - 단일 책임의 원칙에 맞지 않게, 하나의 클래스가 여러가지의 기능을 수행하는 객체를 이르는 말

: 전체 코드의 길이는 늘어나더라도, 클래스 하나의 길이가 짧아지는 편이 낫다!

2. 개방 폐쇄 원칙 (Open-Closed Principle)

: 클래스는 확장에는 열려있어야하며, 수정에는 닫혀 있어야 한다.

: SOLID 원칙의 창시자 Robert C.Martin 왈,

"확장에는 열려 있다는 건 프로그램의 기존 기능을 확장할 수 있다는 것이고,""

"수정에는 닫혀 있다는 건 한 번 작성한 코드를 바꾸지 않아도 된다는 것"

"즉, 어떤 클래스의 코드를 수정하지 않아도 기존 기능을 확장할 수 있어야 한다"

: 다형성을 이용해 개방폐쇄 원칙을 지킬 수 있다. (즉, 추상클래스의 사용!!)

: 더 쉽게 협력하고 더 편하게 수정하기 위해서!

3. 리스코프 치환 원칙 (Liskov Substitution Principle)

: 컴퓨터 과학자 Barbara Liskov의 이름을 따서 만들어졌다.

: 부모 클래스의 인스턴스를 사용하는 위치에 자식 클래스의 인스턴스를 대신 사용해도 코드가 원래 의도대로 작동되어야 한다.

: 자식클래스의 인스턴스는 부모 클래스의 인스턴스 isinstance(자식클래스의 인스턴스, 부모클래스) # True

: 즉, 부모 클래스의 행동규약을 자식클래스가 어기지 말 것 (오버라이딩을 잘못하지 말 것!)

: 오버라이딩을 잘못하는 경우는?

    (1) 형식적인 측면 - 자식 클래스가 부모 클래스의 변수의 타입을 바꾸거나 메소드의 파라미터 또는 리턴값의 타입 or 갯수를 바꾸는 경우

        : 오버라이딩을 할 때는 메소드의 파라미터와 리턴값의 타입과 개수를 맞춰서 오버라이딩할 것!!

        : 오버라이딩하는 메소드 이외에 자식 클래스에서 새롭게 생성한 메소드에서는 (기존에 상속받은 게 없으니까 당연히) 자유롭게 정의하면 된다.

    (2) 내용적인 측면 - 자식 클래스가 부모 클래스의 의도와 다르게 메소드를 오버라이딩하는 경우

         : 파라미터와 리턴값의 타입과 개수와 같은 형식적인 측면은 지켰으나, 메소드의 의도와 다르게 오버라이딩했을 때 발생하는 잘못된 점이기 때문에 디버깅하기 더 어렵다...!!!

         : 서브타이핑 관계를 만족할 것...!! (단순히 코드 재사용을 위한 목적은 서브클래싱, 자식 인스턴스가 부모 인스턴스 위치에 사용하기 위함이면 서브타이핑) 즉, 정사각형과 직사각형은 개념상으로 보면 A는 B다의 관계가 성립되는데, 행동(메소드)가 호환되지는 않는다. 따라서 리스코프 치환 원칙에 위배된다.

     : 리스코프치환원칙은 개발자들끼리 협업할 때 측히 중요하다!

 

4. 인터페이스 분리 원칙 (Interface Segregation Principle)

(인터페이스란? (파이썬에는 없는 개념이긴 하지만) 추상 클래스 중에서 추상 메소드만 있고 일반 메소드는 없는 것)

: 클래스가 사용하지 않을 메소드에 의존할 것을 강요하면 안 된다.

: 즉, 자식클래스에서 사용하지 않을 메소드를 쓰도록 추상클래스에서 추상메소드로 쓰면 안 된다!

: 뚱뚱한 인터페이스 - 너무 많은 메소드를 한번에 갖고 있는 인터페이스

: 뚱뚱한 인터페이스의 여러 역할을 각 역할 인터페이스(role interface)로 나눌 것!

: 이렇게 역할 인터페이스로 나누다 보면 다중 상속을 많이들 하게 되는데, 일반 메소드가 섞여있는 추상클래스는 다중 상속을 하지 않거나, 주의를 기울이는 편이 좋다. 하지만 이렇게 추상 메소드로만 이루어진 인터페이스같은 경우는 어차피 자식 클래스에서 추상 메소드를 오버라이딩해야하기 때문에 다중 상속의 문제점(어떤 부모 클래스의 메소드를 호출하는지를 매번 확인해야하는 문제)가 발생할 일이 없다. 그러니 마음놓고 쪼개고 차라리 다중 상속 받아서 인터페이스 분리 원칙을 지키도록 하자!

 

5. 의존 관계 역전 원칙 (Dependency Inversion Principle)

: 상위 모듈은 하위 모듈의 구현 내용에 의존하면 안 된다. 상위 모듈과 하위 모듈 모두 추상화된 내용에 의존해야 한다.

    (사용하는 모듈 - 상위 모듈/ 사용 당하는 모듈 - 하위 모듈)

: 즉, 상위 모듈이 하위 모듈을 사용할 때, 직접 인스턴스를 가져다가 쓰지 말라는 것...!!

: "인스턴스를 바로 가져다가 쓴다"는 말은, 하위 모듈의 구체적인 내용에 상위 모듈이 의존하게 되어 하위 모듈에 변화가 있을 때마다 상위 모듈의 코드를 자주 바꿔줘야 하기 때문...!!

: 이애 대한 해결책은 추상 클래스(두둥)로 상위 모듈과 하위 모듈 사이에 추상화 레이어를 만드는 것. 이렇게 되면,

    1. 상위 모듈에는 추상 클래스의 자식 클래스의 인스턴스를 사용한다는 가정 하에 그 하위 모듈을 사용하는 코드를 작성해두면 되고,

    2. 하위 모듈은 추상 클래스의 추상 메소드들을 구현(오버라이딩)만 하면 된다.

위와 같이 코딩하면 상위 모듈은 새로운 하위 모듈이 생겨도 기존 코드를 수정하지 않고 새 하위 모듈을 자유롭게 쓸 수 있다.

그런데 이거.. 어디서 많이 봤다? <- 개방-폐쇄 원칙에도 나왔던 내용!!!

사실, 의존 관계 역전 원칙은 개방-폐쇄 원칙을 지키는 하나의 방법😉