[SW공학] SOLID

한결·2023년 11월 1일
0

CS

목록 보기
34/34

출처 및 학습 경로 : 소프트웨어 꼰대강의 유투브

객체지향

객체지향 설계에 등장하는 개념들
클래스 : 공통되는 것들을 묶어서 대표적인 이름을 붙인 것(추상화의 결과)

추상화 : 공통적인 것들을 뽑아낸 것
예를들어 사람, 자동차라고 하면 누구든지 알아들을 수 있는 정도로 공통점만 뽑아내는 것
자동차! 라고 하면 모두가 머릿속에 엔진있고, 바퀴, 창문있는 이동수단인 것을 떠올린다 -> 우리 사이에 이미 추상화가 되어있는 거임, 자동차의 공통적인 것들을 뽑아내서 갖고 있다는 것
소프트웨어를 설계할 때도 마찬가지로 공통적인 것들을 묶어서 클래스로 추상화

인스턴스 : 클래스가 메모리 공간에 할당된 실체
객체 : 명확한 의미를 담고 있는 대상 / 클래스에서 생성된 변수, 상태, 메서드 등

SOLID

OOP의 대표적 원칙

  • SRP - 단일 책임 원칙
    • 하나의 클래스는 하나의 책임만 가진다
  • OCP - 개방 폐쇄 원칙
    • 확장에는 열려있고 변경에는 닫혀있어야한다
  • LSP - 리스코프 교체 원칙
    • 기반 클래스는 파생클래스로 대체할 수 있어야함
  • ISP - 인터페이스 분리의 원칙
    • 하나의 일반적인 인터페이스보다 분리된 구체적인 여러개의 인터페이스가 낫다
    • 기능을 분리해야한다는 말
  • DIP - 의존 관계 역전의 원칙
    • 클라이언트는 구체 클래스보다 추상 클래스에 의존해야한다

SRP (Sungle Responsibility Principal)

로버트 마틴이 "애자일 SW 개발" 책의 '객체지향 설계'부분에서 응집도 원칙을 설명하면서 SRP 개념 소개

  • 클래스는 하나의 책임만 가진다
  • 클래스가 제공하는 모든 서비스(methods)는 그 책임을 수행하는데 집중한다
  • 환경이 바뀌어서 클래스를 변경해야 하는 이유는 오직 하나 뿐이어야 한다
    • 환경 변화로 하나의 클래스가 여러 책임을 갖는 경우 -> 클래스 분할
  • 사람 클래스면 사람 관련된 책임만 수행해야한다. 예를들어, '굴러간다'같은 것은 있으면 안된다는거

장점

  • 클래스 책임 영역 확실 -> 하나의 책임 변경에 따른 연쇄 변경에서 자유롭다
  • 응집도 강화, 결합도 약화, 가독성 향상, 유지보수 용이
    준수 전략
  • 중복된 책임은 추상클래스로 구현
  • 기존의 클래스로 해결할 수 없다면 새로운 클래스 구현


-> 주문 클래스가 1. 주문, 2. 결제 2가지 책임이 있음
-> 분리

OCP (Open Close Principal)

프랑스 사람이 OO SW Construction이라는 책에서 1998에 정의한 내용
"변경에는 닫혀있고 확장에는 열려있어야한다"는 원칙 소개

즉,

  • 기존 요소의 수정을 발행하지 않아야한다
  • 기존 요소를 재활용해서 쉽게 확장할 수 있어야한다

-> 추상화, 다형성이 핵심

-> 변할것, 변하지 않을 것을 모듈로 분리해 관리
-> 만나는 지점을 인터페이스로


주문이라는 클래스에 1.주문, 2.결제 모든 책임이 다있음
-> SRP로 주문 결제 나눔
-> 근데 결제 클래스 결제방법이 다양해지면 매번 클래스를 수정???
-> 결제도 나눠야함

  • 결제 클래스도 나눠야함
  • 이것도 결제 방법이 추가 될때마다 클래스에 변경이 생김

  • PaymentProcess라는 인터페이스에는 변경이 없음
  • 추가되는 결제 방법들은 PaymentProcess를 상속해서 구현
  • 파이썬에선 @abstractmethod로 추상 메서드 구현
  • 자바에는 extends, implements, @override
    • extends 는 오버라이딩 필요없음 & 다중상속 지원안함
    • implements는 반득시 오버라이딩 해야함 & 다중상속 지원

LSP (Liskov Subtitution Principal)

리스코프가 데이터 추상화의 본질을 구성하는 리스코프 치환 원칙 개발

  • 서브타입은 언제나 기반타입으로 교체 가능해야한다
  • 서브타입은 언제나 기반타입과 호환될 수 있어야 한다

-> 기반클래스는 파생클래스로 대체 가능해야한다
즉, 부모클래스의 인스턴스 자리에 파생클래스의 인스턴스가 들어가도 작동해야한다

부모클래스의 속성과 메서드를 그대로 물려받으면 문제가 발생하지 않는데
오버라이딩하면 문제가 발생할 수 있음

예를들어, 자동차클래스에서 헬리콥터라는 파생클래스를 만들었다 가정
기반 클래스인 자동차의 move 메서드는 땅을 달림
-> 따라서 헬리콥터 클래스를 만들때 move가 하늘을 날 수 있도록 오버라이딩
-> 부모클래스의 자동차를 자식인 헬리콥터로 대체할때 move에서 문제 발생
-> LSP 위반함으로써 문제발생
-> 이는 OCP도 붕괴
-> 헬리콥터의 자식클래스인 의료헬리콥터 군용헬리콥터를 변경하면 연쇄적으로
헬리콥터, 자동차 줄줄이 변경해야하기떄문에 변경에는 닫혀있어야하지만 망해버림
-> OOP 자체가 위협

해결방법

  • 추상클래스, 인터페이스 활용
  • 두 객체가 하는일에 무언가를 추가할때 그냥 상속을 활용하기
  • 하는 일이 같으면 하나의 클래스로 구성하고 구분 필드 추가
  • 하는 일이 다르면 그냥 별개의 클래스로 만들어라

즉, 책임을 잘 생각해서 상속, 오버라이딩, 클래스 분리 잘 고려해서 코딩해라

상세 예시

-> PaymentProcessor를 카카오페이로 대체했을 때 동작되지 않을 것이다


-> java는 생성자

ISP (Interface Segregation Principal)

로버트 마틴이 제록스 컨설팅 과정에서 제시한 개념
-> "사용자는 자신이 필요한 인터페이스만 사용"

  • 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다
  • 어떤 클래스가 다른 클래스에 종속될 경우에는 최소한의 인터페이스만 사용
  • 인터페이스를 다수의 작은 단위로 구분하고, 사용자는 자신이 필요한 인터페이스만 사용하도록 구현

구현해놓고 사용안하면 상관없다 생각하지만
필요없는걸 구현해놓고 시스템을 복잡하게 만들고 사용상의 오류를 발생시킬 수 있는 여지를 남기는 행위를 하지 마라

사례


-> P.P를 상속받아서 Sms 인증이 필요없는 결제도 sms인증을 하게됨
-> 에러 발생
-> 모든 클래스가 적절하게 인터페이스를 사용할 수 없음
-> ISP위반

해결방법

  • PP는 pay기능만 구현하고 그 외 구현할 때 상황에 맞게 필요한 클래스를 상속받아 구현
    -> 인터페이스를 더 분리

  • 상속의 깊이는 깊어봐야 1,2단계로 단순화 시키는게 좋음
  • 클래스는 필요한 클래스를 합성하여 구현

DIP (Dependency Inverse Principal)

  • 클라이언트는 구체 클래스가 아닌 추상 클래스에 의존해야한다





-> 구체화 된것에 의존하다가 추상화 된거에 의존하게됨

0개의 댓글