객체지향

객체지향 설계 5원칙 - SOLID원칙

기기디 2022. 4. 5. 23:53

SOLID원칙

  • 객체지향의 5원칙 SOLID는 2000년대 초반 로버트C마틴이 제시하고 마이클페더스가 두문자어로 소개했다.
  • SRP(Single Responsebility Principle) : 단일 책임 원칙
  • OCP(Open Closed Principle) : 개방 폐쇄 원칙
  • LSP(Liskov Subsitituation Principle) : 리스코프 치환 원칙
  • ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
  • DIP(Dependency Inversion Principle) : 의존 역전 원칙
  • 이 원칙들은 결국에 응집도를 높이고 결합도는 낮추라는 관점에서 재정립한것이다.
    • 결합도 : 클래스(모듈)간의 상호의존정도를 나타내며 결합도가 낮으면 의존성의 줄어들어 객체의 재사용이나 수정, 유지보수가 용이하다.
    • 응집도 : 하나의 모듈 내부의 존재하는 구성요소들의 기능적 관련성으로 응집도가 높은 모듈은 하나의 책임에 집중하고 독립성이 높아져 재사용,수정,유지보수가 용이하다
    • 정리 : 객체지향 설계원칙은 개발과정에서 객체의 재사용,수정,유지보수를 용이하게 하는것이 목적이다.
  • SOLID는 제품이나 기술이 아닌 개념이기에 소프트웨어에 녹여서 보여줘야한다.

SRP - 단일 책임 원칙

  • 하나의 클래스에 의존하는 클래스가 많아 한 클래스의 역할과 책임이 많아지는 경우 객체지향에서는 나쁜 냄새가 난다고 표현한다.
  • 단일책임원칙은 클래스에만 해당되는것이 아니라 속성,메소드,패키지,모듈,컴포넌트,프레임워크 등에도 적용할 수 있다.
  • 하나의 속성이 여러 의미를 갖는 경우도 단일책임원칙을 지키지 못하는 경우다. 하나의 필드가 여러개의 의미를 가지게 되면 소스코드에서 불필요한 조건문을 사용하게 된는 경우등이 생겨 비효율적이다.
  • 단일 책임원칙은 모델링 과정을 담당하는 추상화와 가장 깊은 관계를 가지고 있다. 추상화를 통해 설계를 진행할때 단일책임 원칙을 고려해야한다. 또한 리팩토링을 진행할때도 단일 책임 원칙을 적용할 부분이 있는지 늘 살펴야한다.

OCP - 개방 폐쇄 원칙

  • 소프트웨어 엔티티는 확장에 대해서는 열려 있어야 하지만 변경에 대해서는 닫혀 있어야 한다.
  • 예시
    • JDBC인터페이스 : DB가 오라클에서 MySQL로 바뀌더라도 커넥션 설정하는 부분외에는 수정 할 필요가 없다. 비즈니스 로직이 담긴 소스코드는 수정할 필요가 없다. 자바 어플리케이션은 데이터베이스라는 주변의 변화에 대해서는 닫혀 있는것이다. 데이터베이스를 교체한다는것은 데이터베이스가 자신의 확장에는 열려 있다는 뜻이다.
    • 자바 : 개발자는 작성하고 있는 소스코드가 윈도우에서 구동될지 리눅스에서 구동될지 어떤 운영체제에서 구동될지 고려하지 않는다.
    • 스프링프레임워크
  • 객체지향 프로그램에서 개방 폐쇄 원칙을 꼭 따라야하는것은 아니지만 무시하고 프로그램을 작성하면 객체지향프로그래밍에서 가장 큰 장점인 유연성, 재사용성, 유지보수성을 얻기 어렵다.

LSP - 리스코프 치환 원칙

  • 서브타입은 언제나 자신의 기반타입으로 교체할 수 있어야한다.
  • 객체지향 상속의 조건 - 하위 클래스는 상위 클래스의 한 종류다. / 구현클래스는 인터페이스 할 수 있어야한다.(ex. Cloneable - 복제할 수 있어야한다/ Runnable - 실행할 수 있어야한다)
  • 하위 클래스의 인스턴스는 상위클래스 변수에 대입해 상위 클래스의 인스턴스 역할을 하는데 문제가 없어야한다.

ISP - 인터페이스 분리 원칙

  • 클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안된다.
  • SRP원칙을 적용하여 클래스를 분리하기 어려울 때 사용할 수 있는 방법이 인터페이스분할원칙ISP다.
  • 단일책임원칙SRP와 인터페이스분할원칙ISP은 같은 문제를 해결하기 위한 두가지 해결책이다. 프로젝트 요구사항,환경 설계자의 취향 중 하나를 선택 하여 해결할 수 있지만 단일 책임원칙을 적용하는게 더 좋은해결책이다.
  • 인터페이스 최소주의 원칙 : 인터페이스를 통해 메소드를 외부에 제공할때는 최소한의 메소드만 제공하라는것이다. 인터페이스는 그 역할(be able to~)에 충실한 최소한의 기능만 공개하기 위함이다.
  • 빈약한 상위클래스를 사용하는 경우 여기저기 형변환이 발생하면서 상속의 혜택을 제대로 누리지 못한다. 상속의 가장 큰 혜택은 상위클래스형의 참조변수를 이용할 수 있어야한다. 풍성한 상위클래스를 사용하는 경우 불필요한 형변환과 상위 클래스가 사용불가능한 경우가 적다.
  • ? - 추상메서드라는 객체지향기법을 이용하여 다른 기능을 수행하지만 하나의 메소드로 정의되어있는 경우의 문제를 해결할 수 있다

DIP - 의존 역전 원칙

  • 고차원 모듈은 저차원 모듈에 의존하면 안된다. 이 두 모듈 모두 다른 추상화된 것에 의존해야 한다.
  • 추상화된 것은 구체적인 것에 의존하면 안된다. 구체적인 것이 추상화된 것에 의존해야 한다.
  • 자주 변경되는 구체 클래스에 의존하지 마라.
  • 자신보다 변하기 쉬운 것에 의존하던것을 추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 변화에 영향받지 않게 하는 것을 말한다.

정리 - 객체지향세계와 SOLID

  • SOLID원칙은 객체지향과 밀접하게 관계를 맺고 있다. 객체지향 4대 특성을 기반으로 이해해야한다.
  • SoC - 관심사의 분리, Seperation Of Concerns
    • SOLID를 이야기할 때 빼놓을 수 없는 주제로 관심이 같은것 끼리는 하나의 객체 안으로 또는 친한 객체로 모으고 관심이 다른것은 가능한 한 따로 떨어져 서로 영향을 주지 않도록 분리하는것이다.
    • 하나의 속성, 하나의 메소드, 하나의 클래스, 하나의 모듈, 하나의 패키지에는 하나의 관심사만 들어 있어야한다는것이 SoC다.
    • SoC를 적용하다보면 자연스럽게 단일책임원칙SRP, 인터페이스분리원칙ISP, 개방폐쇄원칙OCP에 도달하게 된다.
  • SRP : 어떤 클래스를 변경해야하는 이유는 오직 하나뿐이어야만 한다.
  • OCP : 자신의 확장에는 열려있고, 주변의 변화에는 닫혀있어야한다.
  • LSP : 서브타입은 언제나 자신의 기반타입으로 교체할 수 있어야한다.
  • ISP : 클라이언트는 자신이 사용하지 않는 메소드에 의존관계를 맺으면 안된다.
  • DIP : 자신보다 변하기 쉬운것에 의존하지 마라.
  • SOLID 원칙을 적용하면 소스파일의 개수는 더 많아지는 경향이 있다. 하지만 많아진 파일들은 논리를 더 분할하기 수월하고, 논리를 잘 표현하기에 이해하기 쉽고, 개발하기 쉬우며, 유지관리가 쉬운 소스가 만들어진다.

 

출처 - 스프링 입문을 위한 자바 객체지향의 원리와 이해