본문 바로가기
개발언어/TypeScript

타입스크립트의 객체지향

by Ligion 2021. 4. 15.

OOP

Object-Oriented Programming 객체 지향 프로그래밍


목적

간단히 얘기해서 좋은 프로그램을 만들기위함이다.

기존의 절차지향적 프로그래밍에서 개선된 프로그래밍 패러다임(모형)이다.

하지만 절차지향과 객체지향 각각의 특장단점이 있기에 뭐가 더 좋다라고 할 수는 없지만

만들려는 프로그램을 분석하여 하나만 사용하던 섞던 하면 된다.


방식

큰 틀에서 세분화하는 것이 아니라 세분화된 조각들을 조립하는 것이다.

레고를 떠올리면 가장 쉬운데 여러 모양의 레고들이 있고 이를 설계도 대로 조립을 하면 하나의 완성품이 되는 것처럼 말이다. 이런 조각(=레고)이 바로 객체(Object)이다.


요소

객체지향이라는 것이 의미가 있으려면 아래 4가지 요소들을 이해해야한다.

캡슐화(Encapsulation)

추상화(Abstraction)

상속(Inheritance)

다향성(Polymorphism)


캡슐화 (Encapsulation)

내부와 외부의 상호작용을 컨트롤하는 것.

객체 내부에서만 사용해야하는 데이터와 함수가 있는데 외부에서 사용이 가능하다면 의도가 흐려질 것이다.

이를 방지하기위해 데이터 및 함수의 허용여부(접근제한)를 정의해야하는데 이러한 과정을 캡슐화라고 한다.

 

public : 말 그대로 공개한다는 뜻. 클래스를 인스턴스화(new)하면 마음껏 꺼내 쓸 수 있다.

private : 개인적인이라는 뜻으로 말그대로 비공개하는 것. 클래스 내부에서만 사용가능.

protected : 보호한다는 뜻인데 인스턴스에서는 사용하지 못하며 상속받은 클래스의 내부에서만 사용가능하다.

 

  class Star {
    private name:string;
    constructor(name:string) {
      this.name = name;
    }
    shining() {}
    revolution() {}
  }
  
  const sun:Star = new Star('SUN');
  sun.revolution(); // 공전
  sun.shining();  // 빛을 내다.

 

Star 클래스의 name변수는 인스턴스화해도 꺼내 쓸 수 없으며 오직 생성자에서 주입이 가능하다.

- 접근제한을 사용하지않았으면 기본적으로 public이다.

- 인스턴스화는 new를 사용하며 class라는 틀에서 성격(?), 영혼(?)을 부여하는 것이라고 이해하면 된다.

 

  class Star {
    // 위 코드와 비교하여 이와같이 축약이 가능하다.
    constructor(private name:string) {}
    shining() {}
    revolution() {}
  }

 

[어쩌다 상식]
태양과 같이 빛을 스스로 내는 천체를 항성(Star)이라 한다.
지구와 같이 항성을 공전하는 천체를 행성(Planet)이라 한다.

추상화 (Abstraction)

추상화라는 개념자체가 어려운데 뜻 자체는 단순화와 비슷하지만 이마 저도 애매한 표현이다.

실생활에서 예를 들어 설명하자면

 

박 팀장는 팀원들에게 프리젠테이션을 해야한다.
빔프로젝트와 노트북을 준비하였다.
준비한 빔프로젝트와 노트북으로 팀원들에게 훌륭하게 프리젠테이션을 하였다. 

여기서 빔프로젝트와 노트북은 추상화가 잘 된 것이다. 박팀장이 프리젠테이션을 하는 행위에 빔프로젝트의 작동원리라던가 노트북이 만들어지는 생산라인을 알 필요가 1도 없다. 그 것들을 잘 사용하기만 하면 되기때문이다.

 

const sun:Star = new Star('SUN');
sun.revolution();
sun.shining();

 

Star이라는 클래스의 revolution과 shining이라는 함수가 어떤 로직으로 되어있는지는 모른다.

하지만 어떻게 사용해야하는지 알고 그저 사용하기만 하면 된다.


상속 (Inheritance)

객체지향 중에 가장 쉬운 개념이다. 말그대로 상속하고 받는 것.

부모클래스에서 상속을 받으면 자식클래스는 private되지않은 데이터와 함수들을 그대로 사용할 수 있다.

 

class Gravity {
  revolution() {}
}

class Star extends Gravity {
  constructor(private name:string) {
    super();
  }
  shining() {}
}

class Planet extends Gravity {
  constructor(private name:string) {
    super();
  }
}

const sun:Star = new Star('Sun');
sun.revolution();
sun.shining();

const earth:Planet = new Planet('Earth');
earth.revolution();

 

- extends 옆 상속할 하나의 클래스를 작성.

- super를 통해 연결한다.

 

[어쩌다 상식]
자전의 원인은 중력이 아니라 관성이라 한다.
중력의 정확한 표현은 gravitation(만류인력)이지만 익숙한 gravity로 하자 (어쩌다 이 예제를 했지....)

다향성(Polymorphism)

다향성은 쉽게 말해서 다양하게 만들 수 있다는 것.

기껏 클래스를 만들었는데 하나의 인스턴스밖에 만들지 못한다면 의미가 아무 의미가 없다.

 

class Gravity {
  revolution() {}
}

class Star extends Gravity {
  arounds: Planet[];
  constructor(private name:string) {
    super();
  }
  shining() {}
}

class Planet extends Gravity {
  constructor(private name:string) {
    super();
  }
  revolution() {}
}

const sun:Star = new Star('SUN');
sun.shining();

const aroundTheSun: Planet[] = [
  new Planet('Mercury'),
  new Planet('Venus'),
  new Planet('EARTH'),
  new Planet('Mars'),
];

sun.arounds = aroundTheSun;

 


static

static을 통해서 class level과 instance level을 나눌 수 있다.

 

const sun:Star = new Star('SUN');

 

지금까지는 인스턴스 레벨에서 인스턴스화하였다.

아래와 같이 클래스 레벨에서도 인스턴스화가 가능하다.

 

class Star {
  private constructor(private name:string) {}
  static create(name:string): Star {
    return new Star(name);
  }
  shining() {}
  revolution() {}
}

const sun:Star = Star.create('SUN');

 

create함수는 클래스 레벨에서 인스턴스를 생성하는 함수인데

생성자(constructor)를 private로 감추고 자신의 인스턴스를 리턴하고 static을 붙였다.


getter, setter

 

class Star {
  private constructor(private name:string) {}
  static createStar(name:string): Star {
    return new Star(name);
  }
  shining() {}
  revolution() {}

  private starMass:number;
  get mass() {
    return this.starMass;
  }
  set mass(num:number) {
    this.starMass = num;
  }
}

const sun:Star = Star.createStar('SUN');
sun.mass = 1989; // 태양의 질량은 1.989 × 10^30kg
console.log(sun.mass);

 

getter와 setter는 함수 형태로 되어있고 함수명이 일치해야 된다.

보통 private된 변수와 getter, setter이렇게 세개가 셋트다


composition

 

// Celestial 천체
interface Celestial {
  revolution(): void;
}

class Star implements Celestial {
  constructor(private name:string) {}
  revolution() {}
  shining() {}
}

class Planet implements Celestial {
  constructor(private name:string) {}
  revolution() {}
}

const solarSystem: Celestial[] = [
  new Star('SUN'),
  new Planet('EARTH'),
  new Planet('Mercury'),
  new Planet('Venus'),
  new Planet('Mars'),
];

 

예제가 살짝 애매하지만 개념은 비슷하다고 본다.

위 다향성 예제에서 조금 수정한 것인데

Celestial(천체)라는 개념으로 인터페이스로 바꾸고 각 클래스에서 implements하였다.

다향성 예제에서는 aroundTheSun변수의 타입이 Planet이라서 Planet의 인스턴스들만 삽입이 가능했지만

그보다 상위인 Celestial를 타입으로 지정하면

Star클래스까지 삽입이 가능하여 solarSystem(태양계)라는 변수명에 합당해진다.

'개발언어 > TypeScript' 카테고리의 다른 글

type과 interface 차이  (0) 2021.04.16
제네릭 <Generic>  (0) 2021.04.15
타입 단언 (Type Assertions)  (0) 2021.04.12
타입 추론 (Type Inference)  (0) 2021.04.12
교차타입 (Intersection Types)  (0) 2021.04.12

댓글