객체 지향 프로그래밍(OOP)과 객체

윤뿔소·2024년 8월 3일
0

CS 지식 / 다양한 팁

목록 보기
12/20

함수형으로만 개발하다가 OOP에 대해서 깊게 배울 때가 생겼습니다. 그 지식 습득에 대해 정리해보겠습니다.

다 읽어보시면 플라톤 철학과 OOP의 관계에 대해서도 읽어보세요. 신기한 개념이라 따로 정리해봤습니다.

객체

객체는 데이터와 메소드의 집합으로, 현실의 개념이나 사물을 모델링한 프로그래밍의 기본 단위입니다. 객체는 속성(Property)과 동작(Method)을 가질 수 있으며, 다른 객체와 상호작용할 수 있습니다.

객체와 함수의 비교

  • 객체: 속성과 메소드를 포함하는 데이터 구조로, 상태(state)와 행동(behavior)을 나타냅니다.
  • 함수: 특정 작업을 수행하는 코드의 단위로, 입력을 받아 처리하고 결과를 반환합니다.

객체는 상태와 동작을 함께 가지지만, 함수는 주로 특정 동작만을 정의합니다.

객체 지향 프로그래밍(OOP)

객체 지향 프로그래밍(OOP)은 프로그램을 객체라는 기본 단위로 구성하는 방법론입니다. 주요 개념은 다음과 같습니다.

  • 클래스(Class): 객체를 생성하기 위한 청사진으로, 속성(데이터)과 메소드(동작)를 정의. 객체가 아님(프로토타입 류 언어 제외).
  • 객체(Object): 클래스의 인스턴스(instance)로, 클래스에서 정의한 속성과 메소드를 실제로 구현.
  • 상속(Inheritance): 부모 객체의 속성과 메소드를 자식 객체가 물려받는 것.
  • 캡슐화(Encapsulation): 객체의 데이터를 외부에서 직접 접근하지 못하도록 숨기고, 메소드를 통해 접근하는 것.
  • 다형성(Polymorphism): 동일한 메소드가 다양한 객체에서 다르게 동작할 수 있는 것.
  • 추상화(Abstraction): 복잡한 내부 구현을 숨기고, 필요한 기능만을 외부에 제공하는 것.

OOP 개념이 어렵다면 6살 짜리도 알 수 있는 객체를 참고해주세요. 비유적인 예시가 아주 탁월합니다.

OOP의 예시 및 데이터 흐름

OOP란 다시 말해, 데이터를 객체라는 단위로 묶어서 다루는 프로그래밍 패러다임입니다. 객체는 데이터(속성)와 해당 데이터의 동작(메소드)을 포함합니다.

과일의 특징을 모은 클래스를 만들 때, OOP의 4가지 개념을 적용해 보겠습니다. 속성은 과일 이름, 무게, 색상, 맛으로 제한하겠습니다.
JS는 기존 언어들의 OOP와는 많이 다른 모습을 보여주기에 TS로 예시를 보여주겠습니다.

1. 추상화 (Abstraction)

먼저, 과일의 일반적인 속성과 동작을 정의(추상화)합니다. class Fruit을 만듭니다.

class Fruit {
  constructor(name: string, weight: number, color: string, taste: string) {
    this.name = name; // 과일 이름
    this.weight = weight; // 과일 무게
    this.color = color; // 과일 색상
    this.taste = taste; // 과일 맛
  }

  describe(): string {
    return `${this.name}${this.weight}g 무게를 가지고 있으며, ${this.color} 색상이고, 맛은 ${this.taste}입니다.`;
  }
}

2. 캡슐화 (Encapsulation)

과일의 속성들을 클래스 내에 캡슐화합니다. 거기에 더해서 TS에서 private 키워드를 사용해 속성을 캡슐화할 수 있습니다.

gettterdescribe 메소드로 확인이 가능하도록 만들어줍니다.

// 과일의 특징을 모은 기본 클래스
class Fruit {
  // private 속성들 (캡슐화)
  private name: string;
  private weight: number;
  private color: string;
  private taste: string;

  constructor(name: string, weight: number, color: string, taste: string) {
    this.name = name;
    this.weight = weight;
    this.color = color;
    this.taste = taste;
  }

  // describe 메소드: 과일의 특징을 설명 (추상화)
  describe(): string {
    return `${this.name}${this.weight}g 무게를 가지고 있으며, ${this.color} 색상이고, 맛은 ${this.taste}입니다.`;
  }

  // getter 메소드들: 속성을 외부에서 접근할 수 있게 함 (캡슐화)
  getName(): string {
    return this.name;
  }

  getWeight(): number {
    return this.weight;
  }

  getColor(): string {
    return this.color;
  }

  getTaste(): string {
    return this.taste;
  }
}

3. 상속 (Inheritance)

이제 Fruit 클래스를 상속받아 특정 과일 클래스를 정의해 보겠습니다.

// 사과 클래스 (상속)
class Apple extends Fruit {
  // Apple 클래스의 생성자: 부모 클래스의 생성자를 호출 (상속 및 오버라이딩)
  constructor(weight: number, color: string, taste: string) {
    super('사과', weight, color, taste);
  }
  // describe 메소드: 부모 클래스의 메소드를 오버라이딩 가능 (다형성)
  describe(): string {
    return `이것은 ${super.getName()}입니다. ${super.describe()}`;
  }
}

// 바나나 클래스 (상속)
class Banana extends Fruit {
  // Banana 클래스의 생성자: 부모 클래스의 생성자를 호출 (상속 및 오버라이딩)
  constructor(weight: number, color: string, taste: string) {
    super('바나나', weight, color, taste);
  }
  // describe 메소드: 부모 클래스의 메소드를 오버라이딩 가능 (다형성)
  describe(): string {
    return `이것은 맛있는 ${super.getName()}입니다. ${super.describe()}`;
  }
}

4. 다형성 (Polymorphism)

다형성을 활용해 동일한 describe 메소드를 각 과일에 대해 사용할 수 있습니다.

const apple = new Apple(150, '빨간색', '달콤함');
const banana = new Banana(120, '노란색', '달콤함');

// 각각의 describe 메소드를 호출 (다형성)
console.log(apple.describe()); // 출력: 이것은 맛있는 사과입니다. 사과는 150g 무게를 가지고 있으며, 빨간색 색상이고, 맛은 달콤함입니다.
console.log(banana.describe()); // 출력: 이것은 바나나입니다. 바나나는 120g 무게를 가지고 있으며, 노란색 색상이고, 맛은 달콤함입니다.

클래스 다이어그램

OOP는 데이터 자체가 흩어져 있어서 과정을 그리는 시퀀스 다이어그램 같은 건 안맞고, 어떤 클래스가 어떤 관계를 정의하는지 나타내는 클래스 다이어그램을 사용해야합니다.

이러한 그림을 draw.io 같은 다이어그램 툴을 사용해 정의하면 구조를 한 눈에 파악할 수 있어 매우 유용할 겁니다.

참고: 클래스 관계를 나타내는 화살표들

프로토타입

프로토타입은 JavaScript에서 객체의 특성을 다른 객체에 상속하는 방식입니다. 모든 객체는 다른 객체를 원형(프로토타입)으로 삼아 자신을 정의할 수 있습니다. JavaScript는 프로토타입 기반 언어로, 객체 간의 상속을 프로토타입 체인(prototype chain)을 통해 구현합니다.

  • 프로토타입 체인: 각 객체는 프로토타입에 대한 링크를 보유하며, 이 링크를 따라가면 최상위 프로토타입 객체(Object.prototype)에 도달할 때까지 체인(.)을 형성합니다. 이를 통해 객체는 자신에게 직접 정의된 속성이나 메소드뿐만 아니라 상위 프로토타입을 불러올 수 있습니다.
// class 사용 예제
class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

// 새로운 Person 객체 생성
const alice = new Person('Alice');
alice.greet(); // "Hello, my name is Alice"

위 예제에서는 Person이라는 클래스를 통해 새로운 객체를 만들고, Person.prototype에 메소드를 정의해 모든 Person 객체가 이를 공유하게 했습니다.

Class와 프로토타입의 차이

  • 프로토타입: JavaScript에서 객체 간의 상속을 구현하는 방식으로, 프로토타입 체인을 통해 상속 구조를 형성합니다.
    • 생성자 함수가 그 예입니다.
    • 모든 함수 객체는 저마다 prototype을 가지고 있습니다.
// 생성자 함수 예제
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 프로토타입에 메소드 추가
Person.prototype.greet = function () {
  console.log(`Hello, my name is ${this.name}`);
};

const alice = new Person('Alice', 30);
alice.greet(); // "Hello, my name is Alice"
  • Class: ES6 이후 JavaScript에 도입된 문법으로, 객체 지향 프로그래밍을 보다 직관적이고 명확하게 구현할 수 있습니다.
    • 사실상 프로토타입 기반 상속을 사용하지만, 더 간결하고 이해하기 쉽게 만들어졌습니다.
    • extends 키워드를 사용해 상속을 구현할 수 있으며, super 키워드를 사용해 부모 클래스의 메소드를 호출할 수 있습니다.

📁 참고


추가: 면접에서 OOP와 그 특징에 대해서 서술하라고 한다면?

객체 지향 프로그래밍(OOP)은 소프트웨어 설계 방법론 중 하나로, 현실 세계의 개념을 객체라는 단위로 모델링해 프로그래밍하는 기법입니다. OOP의 주요 특징은 네 가지로 요약할 수 있습니다.

첫째, 추상화(Abstraction)는 복잡한 시스템을 단순화해 중요한 부분만을 노출하는 개념입니다. 이를 통해 복잡한 내부 구현을 숨기고, 사용자에게 필요한 기능만을 제공해 이해와 사용을 쉽게 합니다.

둘째, 캡슐화(Encapsulation)는 객체의 데이터와 메소드를 하나의 단위로 묶고, 외부에서 접근할 수 없도록 보호하는 개념입니다. 이를 통해 데이터 무결성을 유지하고, 객체 간의 상호작용을 제한해 프로그램의 안정성을 높입니다.

셋째, 상속(Inheritance)은 하나의 클래스가 다른 클래스의 속성과 메소드를 물려받아 재사용하는 기능입니다. 이를 통해 코드의 중복을 줄이고, 기존 코드의 수정 없이 기능을 확장할 수 있습니다.

마지막으로, 다형성(Polymorphism)은 동일한 인터페이스를 통해 서로 다른 구현을 사용할 수 있는 능력입니다. 이는 같은 이름의 메소드가 다른 객체에서 다르게 동작할 수 있게 해 유연하고 확장 가능한 코드를 작성할 수 있게 합니다.

이 네 가지 특성을 통해 OOP는 코드의 재사용성, 확장성, 유지보수성을 높이며, 복잡한 소프트웨어 시스템을 보다 효과적으로 관리할 수 있게 합니다.


참고 : OOP를 사용하기 좋은 프로그램

AI로 뽑아봤습니다.

여러 가지 기능과 다양한 모듈이 서로 상호작용하는 대규모 애플리케이션에서 특히 OOP가 필요합니다. 이런 시스템에서는 코드의 유지보수, 확장, 재사용이 중요한데, OOP가 이러한 요구사항을 충족시키기 위해 매우 유용합니다.

  1. 엔터프라이즈 애플리케이션(Enterprise Applications):

    • 대규모 비즈니스 프로세스를 관리하는 시스템으로, ERP(Enterprise Resource Planning), CRM(Customer Relationship Management) 등이 포함됩니다. 이러한 시스템은 다양한 모듈(예: 재무, 인사, 물류 등)이 복잡하게 연동되기 때문에 모듈 간의 관계와 상호작용을 명확히 정의하고 관리할 필요가 있습니다.
  2. 웹 애플리케이션(Web Applications):

    • 전자상거래 플랫폼, 소셜 네트워크, 온라인 교육 플랫폼 등은 다양한 사용자 인터페이스와 백엔드 서비스가 상호작용합니다. OOP를 통해 사용자, 제품, 주문 등의 개념을 객체로 모델링해 데이터와 기능을 체계적으로 관리할 수 있습니다.
  3. 게임 개발(Game Development):

    • 게임은 다양한 캐릭터, 아이템, 환경 등의 요소가 상호작용하는 복잡한 시스템입니다. OOP를 사용하면 각 요소를 객체로 정의해 상속과 다형성을 통해 다양한 캐릭터와 아이템의 동작을 쉽게 확장하고 관리할 수 있습니다.
  4. 분산 시스템(Distributed Systems):

    • 클라우드 기반 애플리케이션, 마이크로서비스 아키텍처 등은 여러 서비스가 네트워크를 통해 상호작용하는 구조를 가집니다. OOP를 통해 각 서비스의 인터페이스와 구현을 분리하고, 객체 간의 메시지 전달을 통해 복잡한 상호작용을 관리할 수 있습니다.
  5. 모바일 애플리케이션(Mobile Applications):

    • 모바일 앱은 사용자 인터페이스(UI)와 백엔드 로직이 밀접하게 연동되며, 다양한 디바이스와 플랫폼을 지원해야 합니다. OOP를 사용하면 UI 요소와 비즈니스 로직을 객체로 분리해 유지보수와 확장을 쉽게 할 수 있습니다.
profile
코뿔소처럼 저돌적으로

0개의 댓글