객체 지향 SOLID 원칙

조창일·2024년 5월 31일

내배캠

목록 보기
33/51
post-thumbnail

단일 책임 원칙 (SRP)

하나의 컴포넌트에는 하나의 기능만!

구현 내용
→ Player 캐릭터 구현

Bad Player
하나의 Player Script

  • 이동처리 → 입력받기, 움직이기
  • 애니메이션
  • 걸어다니는 효과음

Good Player

  • Player
    • 아래 스크립트에서 구현된 기능들을 조합
  • PlayerMovement
    • 이동 관련 기능 구현
  • PlayerAnimation
    • 애니메이션 관련 기능 구현
  • PlayerAudio
    • 플레이어 효과음 구현

Bad와 Good의 차이점
Component가 아닌 script class가 연결되는 것

  • 조합해서 쓰는 코딩이 가능해진다.
    → 각 클래스들이 가지고 있는 함수들을 조합할 수 있다.

개방 폐쇄 원칙 (OCP)

기능 확장을 하려할 때
기존 코드를 수정할 필요 없이 (수정 - CLOSE)
새로운 코드를 작성 (확장 - OPEN)
할 수 있어야 한다.

구현 내용
1. Enemy를 만나면 체력이 깍인다.
2. Enemy의 공격방식은 모두 다르다.
3. Enemy의 종류가 계속 추가된다.

Bad OCP
1. damage 변수를 통해 캐릭터의 체력을 깎아준다.
2. MonsterType enum과 switch 문을 활용
...........a. Type이 많아질 경우 switch 분기가 길어진다.

개발이 빠르고 편리하지만, 나중으로 갈수록 어려워진다.

Good OCP

  • 추상 클래스 Enemy → 똑같은 요소들을 부모 클래스로 빼놓기
    • 충돌 인식 (모든 적들은 충돌 인식을 해야한다)
    • 데미지
    • 공격함수 (abstract)
  • 개별 Enemy : Enemy
    • 몬스터 유형이 추가될 때 Script만 추가
    • 각 공격을 추가함에 있어서 코드 수정 사항이 최소화된다.
    • 다른 스크립트에 영향이 적다.

Bad와 Good의 차이점
1. 몬스터 종류가 늘어남에 따라 해당 몬스터를 위한 Script 내용을 추가해야해서 코드가 계속 길어진다.
2. 하나의 스크립트에 너무 많은 내용들이 포함된다.

리스코프 치환 원칙 (LSP)

자식들에게 "정말 공통적"으로 있을 법한 애들만 부모에 있어야 한다!

구현 내용
1. 모든 새는 점프포인트에 비행해야한다.
2. 새의 종류는 계속 추가된다.
(근데 펭귄, 타조 같이 날지 못하는 새는?)

Bad LSP

  • Bird.cs
    • Cry
    • Fly
  • Bird를 상속받는 새들을 제작
    • 애초에 새들은 난다?
    • 근데 날지 않는 새가 추가된다 → 오류 발생의 시작
  • 자식에서 사용되는 않는 함수는 X
    • 하지만 협업에서도 자주 땜빵을 친다.

Good LSP

  • Bird
    • 진짜 bird에만 존재하는 기능
  • FlyBird : Bird, NotFlyBird : Bird
    • Fly 관련 기능
  • 인터페이스 사용 IFlyable
    • 변동이 있을만한 기능 → Interface
    • 핵심 기능 → 클래스에 담으면 된다.

인터페이 분리 원칙 (ISP)

인터페이스도 책임을 하나만 해라!
단일책임원칙 인터페이스 버전

Bad ISP
1. 하나의 Interface에 Move, Attack, Die 함수 작성

Good ISP

  • IMovable, IAttackable, IDiable 를 작성하고 unit별로 필요한 Interface를 적용

의존성 역전 윈칙 (DIP)

관리하는 상위 객체는 관리만 (On, Off)
하위 객체에서 뭘 하고싶은지 스스로 정하기 (문 여닫기, 불 켜고 끄기, 충전 시작 종료)

구현 내용
1. 스위치로 문을 여닫게 만들어야함
2. 뿐만 아니라 불도 끄고 켜거나
3. 충전을 진행시키거나 멈추거나 해야함.

Bad DIP
1. 하나의 Switch 클래스에서 문, 불, 충전을 모두 open, close
2. Swich를 하려면 각 객체들을 직접 받아와서 Door.Opne(), Light.Opne()~~

Good DIP

  • 인터페이스를 활용해서 문 : ISwitchable, 불 : ISwitchable, 충전 : ISwitchable
  • 하지만 인터페이스를 public으로 선언하더라도 Inspector에서 활용 불가
    • GameObject를 Inspector에 넣어서 GetComponenet방식으로 활용

장점

  • 전혀 다른 객체들도 사소한 공통점을 통해 묶어줄 수 있다!

But

  • 객체지향이 오히려 복잡성을 증가시킬 수 있다. 적절히 유도리 있게 사용!

왜 알아야 할까?

  • 다른 사람의 코드를 이해하고 효율적인 추가적인 기능 구현을 하기 위해서
profile
안녕하세요.

0개의 댓글