TypeScript Study day-3 _ OOP

hwibaski·2021년 12월 20일
0

TypeScript & JavaScript

목록 보기
11/15

드림코딩엘리님의 TypeScript 강의를 토대로 정리했습니다.

1. 객체지향 프로그래밍이란?

프로그래밍 패러다임 중 하나로 객체를 기반으로한 프로그래밍을 한다. 객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 "객체"들의 모임으로 파악하고자 하는 것이다. 각각의 객체는 메시지를 주고받고, 데이터를 처리할 수 있다.

  1. 생산성
  2. 높은 퀄리티
  3. 빠르고, 유지보수가 용이하다.

1.1 클래스와 객체의 차이

클래스

  • 객체를 만들기 위한 템플릿
  • 작성 시 한 번만 선언한다.
  • 실제로 데이터가 들어가지 않는다.

객체

  • 클래스를 이용하여 만든 각각의 객체는 그 클래스의 인스턴스이다.
  • 여러개로 만들어질 수 있다.
  • 실제로 데이터가 들어간다.

1.2 객체지향의 원칙

각각의 특징에 대한 설명은 더 공부한 후 추가 예정.

  • 캡슐화(Encapsulation)
  • 추상화(abstraction)
  • 상속성(inheritance)
  • 다형성(polymorphism)

2. 절차지향적으로 커피기계 만들기

  • 관련된 변수, 상수, 메서드들이 묶여 있지 않고, 파편화되어 있다.
// makeCoffee가 리턴할 객체의 타입을 정의
type CoffeeCup = {
  shots: number;
  hasMilk: boolean;
};

// 하나의 샷에 소모되는 커피콩의 그람(g)을 상수로 정의, 임의로 하나의 샷에 7g이 소모된다고 가정
const BEANS_GRAMM_PER_SHOT: number = 7;

// 우리가 가지고 있는 커피 콩의 양, 현재는 0이라고 가정
let coffeeBeans: number = 0;

// 커피를 만드는 함수, 몇 잔을 만들지 shots 매개변수로 받는다.
function makeCoffee(shots: number): CoffeeCup {
  // 우리가 가지고 있는 커피콩의 양의 샷의 숫자와 BEANS_GRAMM_PER_SHOT의 곱보다 작으면 error
  if (coffeeBeans < shots * BEANS_GRAMM_PER_SHOT) {
    throw new Error('Not enough coffee beans!');
  }
  // 커피를 만들었기 때문에, 우리가 가지고 있는 coffeeBeans를 줄여줘야 한다.
  coffeeBeans -= shots * BEANS_GRAMM_PER_SHOT;
  // 정상적으로 작동시 아래의 객체를 리턴
  return {
    shots,
    hasMilk: false,
  };
}
	
// const coffee = makeCoffee(2); -> 우리가 가지고 있는 커피콩이 0이기 때문에 error를 던진다.
	
// 커피콩의 숫자를 늘려준다.
coffeeBeans += 3 * BEANS_GRAMM_PER_SHOT;
const coffee = makeCoffee(2)
console.log(coffee); // { shots: 2, hasMilk: false }

객체지향적으로 코딩하기

  • 서로 관련 있는 데이터 및 함수들을 한 곳에 모아놓을 수 있다.
  • 생성할 객체의 청사진(템플릿)을 제공한다.
type CoffeeCup = {
  shots: number;
  hasMilk: boolean;
};

class CoffeeMaker {
  // 멤버변수, 속성
  // BEANS_GRAMM_PER_SHOT은 어떠한 인스턴스이던 간에 7로 고정되어 있다.
  // 굳이 인스턴스마다 중복적으로 데이터를 생성하여 이 값을 가지고 있을 필요가 없다. -> 메모리의 낭비
  BEANS_GRAMM_PER_SHOT: number = 7;
  coffeeBeans: number = 0;

  // class를 가지고 obejct instance를 만들 때 항상 호출이 된다.
  constructor(coffeeBeans: number) {
    // constructor에서 인수를 받아서 멤버변수의 coffeeBeans에 할당한다.
    this.coffeeBeans = coffeeBeans;
  }

  makeCoffee(shots: number): CoffeeCup {
  // class 내에서 멤버변수에 접근하기 위해서는 this를 붙혀줘야한다.
    if (this.coffeeBeans < shots * this.BEANS_GRAMM_PER_SHOT) {
      throw new Error('Not enough coffee beans!');
    }
    this.coffeeBeans -= shots * this.BEANS_GRAMM_PER_SHOT;
    return {
      shots,
      hasMilk: false,
    };
  }
}

// new 연산자는 CoffeeMaker의 인스턴스를 생성한다.
// CoffeeMaker 뒤의 '()' 는 생성자 함수를 실행한다.
const maker = new CoffeeMaker(32);
console.log(maker); // CoffeeMaker { BEANS_GRAMM_PER_SHOT: 7, coffeeBeans: 32 }
const maker2 = new CoffeeMaker(17);
console.log(maker2); // CoffeeMaker { BEANS_GRAMM_PER_SHOT: 7, coffeeBeans: 17 } 

static

  • 클래스는 넣어주는 데이터에 따라서 메소드나 필드가 바뀌는 것이 특징이다.
  • 하지만 들어오는 데이터에 따라 변하는 것이 아닌 항상 고정으로 지정된 값들이 필요할 수 있다. 이럴 때 static을 사용한다.
  • BEANS_GRAMM_PER_SHOT은 어떠한 인스턴스이던 간에 7로 고정되어 있다. (어떠한 커피메이커든 간에 한 샷에 7g이 소모된다는 가정하에...)
  • 굳이 인스턴스마다 중복적으로 데이터를 생성하여 이 값을 가지고 있을 필요가 없다. -> 메모리의 낭비
  • class 내에서 static으로 선언한 멤버변수에 접근할 때는 this가 아닌 class의 이름으로 접근해야 한다.
type CoffeeCup = {
  shots: number;
  hasMilk: boolean;
};

class CoffeeMaker {
  // 멤버변수, 속성
  // BEANS_GRAMM_PER_SHOT은 어떠한 인스턴스이던 간에 7로 고정되어 있다.
  // 굳이 인스턴스마다 중복적으로 데이터를 생성하여 이 값을 가지고 있을 필요가 없다. -> 메모리의 낭비
  static BEANS_GRAMM_PER_SHOT: number = 7; // class level
  coffeeBeans: number = 0; // instance level

  constructor(coffeeBeans: number) {
    this.coffeeBeans = coffeeBeans;
  }
  // static을 사용하여 클래스 내부에서 스스로 인스턴스를 만들어서 리턴하는 메서드를 정의할 수 있다.
  static makeMachine(coffeeBeans: number): CoffeeMaker {
    return new CoffeeMaker(coffeeBeans);
  }

  makeCoffee(shots: number): CoffeeCup {
    // static으로 선언한 멤버변수는 클래스의 이름을 붙혀줘야한다.
    if (this.coffeeBeans < shots * CoffeeMaker.BEANS_GRAMM_PER_SHOT) {
      throw new Error('Not enough coffee beans!');
    }
    this.coffeeBeans -= shots * CoffeeMaker.BEANS_GRAMM_PER_SHOT;
    return {
      shots,
      hasMilk: false,
    };
  }
}

const maker = new CoffeeMaker(32);
console.log(maker); // CoffeeMaker { coffeeBeans: 32 }

const maker2 = new CoffeeMaker(17);
console.log(maker2); // CoffeeMaker { coffeeBeans: 17 }

// static을 사용하기 위해 클래스의 이름으로 접근하는 예
const maker3 = CoffeeMaker.makeMachine(10);
console.log(maker3); // CoffeeMaker { coffeeBeans: 10 }
console.log(CoffeeMaker.BEANS_GRAMM_PER_SHOT); // 7

/**
 * Math.max(), Math.min() 등이 static으로 선언된 메소드들을 불러오는 예이다.
 *  Math.max()를 사용할 때 const math = new Math() 를 하지는 않는다.
 */

reference

https://mong-blog.tistory.com/entry/%ED%81%B4%EB%9E%98%EC%8A%A4class%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80

0개의 댓글