내일배움캠프 - TIL/내일배움캠프 - TIL

내일배움캠프 24일차 - 객체 지향 프로그래밍 OOP

rudals4469 2025. 5. 21. 21:38

💡 객체지향 프로그래밍 (OOP, Object-Oriented Programming)

객체를 중심으로 코드를 구성하여, 복잡한 구조를 단순화하고 유지보수를 용이하게 하는 프로그래밍 패러다임


🔍 OOP의 필요성

  1. 인간은 패턴을 발견하고 활용하려는 존재

 

   2. 요구사항은 항상 변한다

  • 예: “근거리/원거리 몬스터 구분해주세요”, “보스도 추가해주세요” 등

➡ 데이터를 속성과 행동으로 묶어 관리하면, 변화에 유연하고 유지보수하기 쉬운 코드 작성이 가능해짐

 

 


💡 객체란?

  • **속성(데이터)**과 **행동(메서드)**을 가지는 독립적인 단위
  • 직관적으로 “우리가 지칭할 수 있는 것들”.


🧱 객체지향 프로그래밍의 핵심 개념

1. 상속 (Inheritance)

  • 기존 클래스(부모)의 기능을 새로운 클래스(자식)가 재사용 및 확장
  • 코드 재사용성과 계층 구조 형성에 유리

2. 추상 클래스 (Abstract Class)

  • 인스턴스화 불가, 상속 전용
  • 자식 클래스에게 반드시 구현해야 할 메서드를 지정

3. 인터페이스 (Interface)

  • 메서드의 시그니처만 정의
  • 다양한 클래스에 공통된 동작을 강제
  • 예: 몬스터, 덫, 함정 등에서 “공격 가능”이라는 공통 행동을 정의


🧭 객체지향 설계 5대 원칙 (SOLID)

1. SRP - 단일 책임 원칙

하나의 클래스는 하나의 책임만을 가져야 합니다.
즉, 하나의 클래스가 하나의 기능만을 담당해야 하며, 관련 없는 기능이 섞이지 않아야 합니다.
이 원칙을 지키면 변경이 필요한 경우에도 영향을 받는 코드의 범위가 줄어들어 유지보수가 쉬워집니다.

SRP_1
SRP_2

2. OCP - 개방/폐쇄 원칙

확장에는 열려 있고, 수정에는 닫혀 있어야 한다는 원칙입니다.
새로운 기능이 추가되거나 요구사항이 바뀌었을 때, 기존 코드를 수정하지 않고도 기능을 확장할 수 있도록 설계해야 합니다.
이는 기존 코드의 안정성을 보장하고, 새로운 요구사항에도 유연하게 대처할 수 있게 해줍니다.

 

OCP_1
OCP_2

3. LSP - 리스코프 치환 원칙

자식 클래스는 언제나 부모 클래스를 대체할 수 있어야 한다는 원칙입니다.
즉, 부모 클래스를 사용하는 코드가 자식 클래스로 바뀌더라도 그 기능이 올바르게 동작해야 합니다.
이를 통해 클래스 간의 관계를 더욱 견고하게 만들 수 있습니다.

 

LSP_1
LSP_2

4. ISP - 인터페이스 분리 원칙

클래스는 **자신이 사용하지 않는 기능(메서드)**에 의존하지 않아야 합니다.
즉, 하나의 큰 인터페이스보다는, 목적에 맞게 작고 구체적인 인터페이스를 여러 개로 나누는 것이 좋습니다.
이렇게 하면 객체가 필요하지 않은 기능을 억지로 구현하지 않아도 되어 코드가 깔끔해집니다.

 

ISP_1
ISP_2

5. DIP - 의존관계 역전 원칙

상위 모듈(비즈니스 로직)이 하위 모듈(구체적 구현)에 의존해서는 안 됩니다.
모듈 간의 의존은 **구체적인 클래스가 아니라, 추상화(인터페이스나 추상 클래스)**에 의존해야 합니다.
이 원칙을 지키면 객체들 간의 결합도를 낮추고, 유연하고 테스트 가능한 구조를 만들 수 있습니다.

 

DIP_1

 

DIP_2
DIP_3

🧩 static 키워드란?

  • 인스턴스를 생성하지 않고도 접근 가능한 클래스 멤버
  • 모든 인스턴스가 공유

✅ 정적 변수 (Static Field)

정적 변수는 모든 인스턴스가 하나의 값을 공유합니다.
어떤 클래스의 인스턴스를 여러 개 만들더라도, 해당 정적 변수는 딱 하나만 존재하며, 모든 인스턴스에서 동일한 값을 참조하게 됩니다.

예를 들어, 전체 플레이어 수를 세는 playerCount 같은 변수는 static으로 선언하면 좋습니다.
어느 인스턴스에서 값을 증가시켜도, 다른 인스턴스에서도 동일한 값이 유지됩니다.

 

정적 변수

✅ 정적 메서드 (Static Method)

정적 메서드는 클래스 인스턴스를 생성하지 않아도 호출할 수 있는 메서드입니다.
해당 메서드는 인스턴스의 상태(즉, 멤버 변수들)에는 접근할 수 없고, 정적 변수나 외부 전달된 값만 사용할 수 있습니다.

대표적인 예는 Mathf.Abs(), Mathf.Sin() 등과 같은 유틸리티 함수입니다.
이런 메서드는 객체 상태와 무관하게 동작하기 때문에, static으로 정의하는 것이 적합합니다.

 

정적 메서드

✅ 정적 클래스 (Static Class)

정적 클래스는 인스턴스를 생성할 수 없고, 그 안에 있는 모든 멤버가 정적이어야 합니다.
주로 **도우미 기능(Helper)**이나 유틸리티 기능을 묶을 때 사용됩니다.

정적 클래스는 메모리상에서 한 번만 생성되며, 인스턴스를 만들 수 없기 때문에 자원을 아끼고 코드 사용도 명확해집니다.

 

정적 클래스

 


🏗️ 클래스 구조를 어떻게 짜야 할까?

  • 클래스 = 객체를 코드로 표현한 설계도
  • 객체 = 속성과 행동이 있는 독립적인 개념
  • 정답은 없지만…
    • 자연스럽게 생각되는 단위로 먼저 구성
    • 이후 상속, 추상화, 인터페이스, SOLID 원칙 등을 통해 구조를 개선

🔁 반복적인 리팩토링을 통해 자신만의 코딩 습관이 생기게 됨


🧠 Tip

  • “모든 인스턴스는 객체지만, 모든 객체가 인스턴스는 아니다.”
    • C#에서는 int 같은 기본 타입조차도 객체로 간주됨