상세 컨텐츠

본문 제목

객체지향 개발의 5원칙 "SOLID" (객체 지향 설계)

How To Java/For Better Developers

by 카페코더 2020. 2. 12. 16:18

본문

반응형

취업 준비를 하며 복습한다는 마음으로, 이것을 보는 누군가에게 도움이 되었으면 하는 마음으로
객체지향 개발의 5원칙을 작성해 봅니다. 제가 아는 정보가 틀렸을 수 있습니다. 
이 글에 대한 잘못된 정보나, 오탈자 등 수정해야 할 항목 혹은 추가해야 할 항목은 댓글로 알려주시면 감사하겠습니다.

이 자료가 올라가는 저장소 :
https://github.com/hwk0911/Java-tutorial

 

hwk0911/Java-tutorial

Java tutorial. Contribute to hwk0911/Java-tutorial development by creating an account on GitHub.

github.com

SOLID란 로버트 마틴이 2000년대 초반 명명한 객체지향 프로그래밍 및 설계의 
다섯 가지 기본 원칙을 마이클 페더스가 두문자어 기억술로 소개한 것이다.

1. 객체지향 개발 5원칙 "SOLID"의 필요성

객체지향은 하나 이상의 클래스들이 모여 하나의 프로그램을 이룬다.
프로그램이 그 시점에서 필요한, 이번만 쓰고 버릴 프로그램을 만드는 경우는 극히 드물다.
이런 이유로 대부분의 프로그램은 유지보수 및 확장이 필연적으로 일어날 수 밖에 없다.
이 작업을 비교적 쉽게 진행할 수 있게하는 일종의 약속이 객체지향 개발의 5원칙 "SOLID"다.

1.1 객체지향 개발 5원칙의 장점

  1. 코드의 재사용성이 높다.
  2. 코드의 관리가 용이하다.
  3. 신뢰성이 높은 프로그래밍을 가능하게 한다.

Java에서만 해당되는것이 아닌 객체지향 프로그래밍 전체를 관통하는 주제다.

2. 객체지향 개발의 5원칙 앞글자가 모여 "SOLID"

Single Responsiblity Principle (SRP)

Open-Closed Principle (OCP)

Liskov Substitution Principle (LSP)

Interface Segregation Principle (ISP)

Depedency Inversion Priciple (DIP)

3. 각 원칙의 정의

3.1 SRP (단일 책임 원칙)

한 클래스, 함수는 하나의 책임만 가져야 한다.
그 책임은 완전히 캡슐화되어야 한다.

이때 '책임'은 하나의 기능으로 생각하면 이해가 쉽다. 즉 클래스를 수정할 이유는 오직 하나여야 한다는 의미이다.
우리가 쉽게 접하는 게임으로 예를 들자면, 무기의 성능을 구현하는 클래스와 무기의 외형을 구현하는 클래스는
분리되어야 한다. 아래의 다이어그램을 살펴보자.

SRP위반 다이어그램

다이어그램을 보면, 데미지를 계산하는 어플리케이션과, 그래픽에 관련된 어플리케이션이 Weapon 클래스를 참조한다.
위와 같은 설계는 SRP를 위반하는 설계인데, Weapon 클래스가 weaponStatus와 draw 두개의 책임을 갖기 때문이다.
이런 설계는 Weapon 클래스를 수정하였을때 참조하는 어플리케이션에 의도하지 않은 영향을 준다.

SRP를 지켜 설계한 다이어그램은 다음과 같다.

SRP설계 다이어그램

위와 같은설계는 완전히 독립된 클래스를 선언해 각각 하나의 책임을 갖도록 분리하여 설계한 다이어그램이다.
데미지를 계산하는 클래스를 새로 선언해 더이상 총의 외형을 구현하는 기능에 영향을 받지 않는다.

처음 책임을 설명할 때, 기능으로 생각하면 이해가 쉽다고 얘기했고, "클래스를 수정할 이유는 오직 하나여야 한다"
고 설명했다. 이 내용을 생각해보면 SRP가 지켜진 설계인지 쉽게 확인할 수 있다.
클래스를 수정할 때, 두개 이상의 영향이 생긴다면, SRP가 지켜지지 못한 설계라는 의미이다.
줄줄이 영향이가는 설계는 좋지 못한 설계이다.

3.2 OCP (개방, 폐쇄 원칙)

소프트웨어 요소는 확장에는 열려 있으나, 변경에는 닫혀 있어야 한다.

  • 확장에 대해 열려있어야 한다.

    클래스의 동작을 확장할 수 있다는 것을 의미한다. 즉, 애플리케이션의 요구사항이 변경될 때,
    이 변경에 맞게 새로운 동작을 추가해 확장할 수 있어야 한다.

  • 수정에 대해 닫혀있어야 한다.

    클래스의 동작을 추가로 선언할 때, 클래스 자체의 수정이 일어나서는 안된다.

    예를 들어, 무기 클래스가 존재하고, 이것을 사용하는 근접 무기, 원거리 무기 클래스가 구현되어 있다 가정하자.
    이 둘을 데미지 계산기가 사용한다 했을 때, OCP위반이 발생한다. 만약, 마법 무기 클래스를 추가한다면,
    데미지 계산기 클래스의 수정이 발생하기 때문이다.

OCP위반을 방지는 인터페이스(Interface)나 추상 클래스(abstract class)의 선언과 이것을 상속하여 클래스를
선언 하는것을 통해 비교적 쉽게 가능하다.

OCP위반 다이어그램

UML다이어그램 그리기 연습을 덜 해서, 화살표 모양을 헷갈렸다...
의존 관계는 아래의 화살표처럼 표현해야 맞다.

OCP설계 다이어그램

새로운 무기 타입을 추가할 때 마다 기존의 클래스는 영향을 받지 않는다.
이런 방식으로 설계를 하면, 확장에는 열려있고, 수정에는 닫혀있는 설계가 된다.
이것은 단위테스트를 진행할 때 매우 중요하며, 유용하게 작용 한다.

3.3 LSP (리스코프 치환 원칙)

프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.

서브타입은 언제나 자신이 기반타입(base type)으로 교체할 수 있어야 한다.

유도된 클래스의 메소드를 퇴화시키거나 불법으로 만드는 일을 피하라. 기반 클래스의
사용자는 그 기반 클래스에서 유도된 클래스에 대해 아무것도 알 필요가 없어야 한다.

출처 : java 프로그래머를 위한 UML 실전에서는 이것만 쓴다!

위 내용들을 종합하여 쉽게 풀면, 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 한다.
로 볼 수 있다. 즉 일반화 관계에 대한 원칙이다.

예를 들어, 창과 근접무기의 관계를 보자. 누가봐도 근접무기 = 부모 클래스, 둔기 = 자식 클래스 로 볼 수 있다.
이때 자식 클래스인 창이 부모 클래스인 근접무기의 기능을 수행 가능한지 확인해보자.

  1. 근접 무기(둔기)는 공중의 몬스터를 공격할 수 없다.
  2. 근접 무기(둔기)는 적에게 직접적인 공격을 가한다.
  3. 근접 무기(둔기)는 사용자의 힘에 따라 공격력이 달라진다.

위와 같이 근접 무기의 특징이 둔기의 특징에 적용이 가능하다.

예시와 마찬가지로, 부모 클래스가 수행하는 일을 자식 클래스가 가능하다면 LSP에 맞게 설계되었다 볼 수 있다.

 

3.4 ISP (인터페이스 분리 원칙)

특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.

클라이언트는 자신이 사용하는 메소드에만 의존해야 한다는 원칙이다.
예를 들어, 게임 클라이언트를 구성하는 데, 관련된 인터페이스가 아닌 공부와 관련된 메소드를 implement 하면 안된다.
우리는 게임을 할 땐 공부를 하지 않는 것 처럼 각 각 독립된 인터페이스로 설계해야 한다.

언젠간 쓰겠지 하는 마음으로 하나의 거대한 인터페이스를 선언하는 것은 바보같은 행동이다.
의미없는 코드들은 늘어나고, 구조도 깔끔하지 못하다.

3.5 DIP (의존관계 역전 원칙) 

프로그래머는 "추상화"에 의존해야지, 구체화에 의존하면 안 된다.

상위 클래스는 하위 클래스에 의존해서는 안된다는 아주아주 당연한 원칙이다. 

언터페이스는 변하지 않는 것 으로 선언하고, 구체 클래스는 변하기 쉬운 것 으로 설계해야 한다.
DIP를 위반한 다이어그램은 다음과 같다.

DIP위반 다이어그램

Weapon 클래스가 WeaponType 인터페이스에 의존하고, WeaponType 인터페이스는 근접, 원거리, 마법 무기로 부터
상속 받는 내용이다. 이 경우 인터페이스는 변하기 쉬운 것으로 선언했고, 구체 클래스는 고정된 것으로 선언했다.

DIP를 완벽하게 위반한 다이어그램이다.

반응형

'How To Java > For Better Developers' 카테고리의 다른 글

더 나은 개발자를 위해  (0) 2020.02.11

관련글 더보기

GitHub 댓글

댓글 영역