[TypeScript] OOP 객체지향

김래영·2021년 3월 13일
3

TypeScript

목록 보기
3/3

객체지향이란?


서로 관련 있는 데이터와 함수를 객체(하나의 역할을 수행하는 메소드와 변수의 묶음)로 정의해서 서로 상호작용할 수 있도록 프로그래밍 해나가는 것을 말한다. 각각의 객체는 메시지를 주고받고, 데이터를 처리할 수 있다.

장점

객체지향을 사용하면 중복되는 관련 객체를 재사용할 수 있어 코드의 중복을 어느 정도 줄일 수 있고 관련 있는 객체들의 역할 분담을 좀 더 확실하게 할 수 있어서 가독성이 높아질 수 있다.

  • 생산성을 높여준다.
  • 유지 보수 및 확장성이 높다.

참고-위키백과
참고-나무위키

객체지향 요소


캡슐화(Encapsulation)

  • 서로 연관되어 있는 데이터와 함수들을 캡슐화하는 것을 말한다.

정보 은닉(Infomation Hiding)

프로그램의 세부 구현을 외부로 드러나지 않도록 특정 모듈 내부로 감추는 것이다.
서로 연관 있는 데이터와 함수들을 오브젝트 안에 담아두고 외부에서 보일 필요가 없는 세부 데이터를 숨겨 높음으로 외부에서 내부 데이터를 변경할 수 없도록 할 수 있다.
일반적으로 세 종류의 접근 제한이 사용된다.

constructor

  • class를 가지고 instance(object)를 만들 때 항상 호출되는 함수로 데이터를 담아 호출할 수 있다.
  • static 이란 키워드를 사용해서 object를 만드는 함수를 제공한다면 private constructor로 설정해두어 static method를 사용할 수 있도록 권장한다.

public

  • 클래스의 외부에서 사용 가능하도록 노출시키는 것이다.
  • 외부에서 데이터를 확인 또는 변경할 수 있다.
  • class 안에서 변수나 함수에 따로 키워드를 사용하지 않으면 기본적으로 public 상태이다.

private

  • 클래스의 내부에서만 사용되며 외부로 노출되지 않는다.
  • 외부에서 데이터를 확인 또는 변경할 수 있다.

protected

  • 다른 클래스에게는 노출되지 않지만, 상속받은 자식 클래스에게는 노출되는 것이다.
  • 외부에서 접근할 수 없고 상속받은 class만이 접근이 가능하다.

class Animal {
  private emotion: string = '';
  private energy: number = 0;
  
  constructor(
    private animalType: string, 
    private name: string, 
    private gender: string
  ) {
    this.animalType = animalType;
    this.name = name;
    this.gender = gender;
  }
  play() {
    this.emotion = 'happy';  
  }
  eat(food: number) {
     this.energy =  food;
  }
}

const dog = new Animal('dog', 'sam', 'male');
const cat = new Animal('cat', 'jang', 'female');

추상화

  • 내부의 복잡한 기능 private 키워드를 사용해 외부에서 보이지 않도록 함으로서 외부에서 보이는 인터페이스(함수)만을 통해 내부 기능을 이해하지 않아도 사용할 수 있다.

예를 들어, eat , play 함수를 사용하면서 외부에서는 에너지나 감정이 변화하는 함수를 이해하지 않아도 사용할 수 있다.

class Animal {
  private emotion: string = '';
  private energy: number = 0;
  
  constructor(
    private animalType: string, 
    private name: string, 
    private gender: string
  ) {
    this.animalType = animalType;
    this.name = name;
    this.gender = gender;
  }
  
  private energyUp (energy: number) {
    this.energy = energy;
  }
  
  private energyDown () {
    this.energy -=- 1;
  }
  
  private happyEmotion () {
    this.energyDown();
    this.emotion = 'happy';
  }
  
  play() {
    this.happyEmotion();
  }
  
  eat(food: number) {
     this.energyUp(food);
     this.happyEmotion();
  }
}

const dog = new Animal('dog', 'sam', 'male');

dog.eat();
dog.play();

상속

  • 상속을 사용하여 코드의 재사용성을 높일 수 있다.

extends

  • extends라는 키워드를 사용하여 class를 상속받을 수 있다.
  • 상속을 할 때 constructor가 private일 경우 상속이 되지 않는다. public 또는 자식 클래스에서 접근이 가능하도록 protected 키워드를 사용해야 한다.
  • 자식 클래스가 부모 클래스의 함수를 이용하고 싶다면 super 키워드로 접근할 수 있다.
  • 자식 클래스에서 constructor는 반드시 super를 호출해야 하며 부모 클래스에서 필요한 데이터를 super를 이용해 전달해 주어야 한다.

상속의 단점: 타입스크립트에서 상속은 두가지 이상 상속받을 수 없으며 부모클래스의 변화가 있을 경우 자식 클래스도 영향을 미치는 단점이 있다.

class Animal {
  private emotion: string = '';
  private energy: number = 0;
  
  constructor(
    private animalType: string, 
    private name: string, 
    private gender: string
  ) {
    this.animalType = animalType;
    this.name = name;
    this.gender = gender;
  }
  
  private energyUp (energy: number) {
    this.energy = energy;
  }
  
  private energyDown () {
    this.energy -= 1;
  }
  
  private happyEmotion () {
    this.emotion = 'happy';
  }
  
  play() {
    this.happyEmotion();
  }
  
  eat(food: number) {
     this.energyUp(food);
     this.happyEmotion();
  }
}


class Dog extends Animal {
  constructor(animalType, name, gender) {
    super(animalType, name, gender)
  }
  
  barking() {
    super.energyDown();
    return 'wang wang';
  }
}

const seryDog = new Dog('dog', 'sery', 'female');
seryDog.barking();

다형성

  • 상속을 통해서 만들어진 자식 클래스들의 종류와 상관없이 부모 클래스에 정의된 함수를 호출할 수 있다.
class Animal {
  private emotion: string = '';
  private energy: number = 0;
  
  constructor(
    private animalType: string, 
    private name: string, 
    private gender: string
  ) {
    this.animalType = animalType;
    this.name = name;
    this.gender = gender;
  }
  
  private energyUp (energy: number) {
    this.energy = energy;
  }
  
  private energyDown () {
    this.energy -=- 1;
  }
  
  private happyEmotion () {
    this.emotion = 'happy';
  }
  
  play() {
    this.energyDown();
    this.happyEmotion();
  }
  
  eat(food: number) {
     this.energyUp(food);
     this.happyEmotion();
  }
}


class Dog extends Animal {
  constructor(animalType, name, gender) {
    super(animalType, name, gender)
  }
  ...
  barking() {
    super.energyDown();
    return 'wang wang';
  }
  ...
}

class Cat extends Animal {
  constructor(animalType, name, gender) {
    super(animalType, name, gender)
  }
  ...
  play() {
    super.play();
  }
  ...
}

const seryDog = new Dog('dog', 'sery', 'female');
seryDog.barking();

static

  • 변수나 함수에 static이라는 키워드를 사용하면 class level로 지정된고 static이 사용하지 않으면 object level이다.
  • class level은 class와 연결되어 있기 때문에 instance마다 만들어지거나 생성되지 않는다.
  • object level은 this를 사용해 접근할 수 있고 class level을 사용할 때 class 이름으로 접근할 수 있다.
class Animal {
  static private emotion: string = '';
  static private energy: number = 0;
  
  constructor(
    private animalType: string, 
    private name: string, 
    private gender: string
  ) {
    this.animalType = animalType;
    this.name = name;
    this.gender = gender;
  }
  
  static makeAnimal (animalType: string, name: string, gender: string) {
    return new Animal(animalType, name, gender)
  }
  
  private energyUp (energy: number) {
    Animal.energy = energy;
  }
  
  private energyDown () {
    Animal.energy -=- 1;
  }
  
  private happyEmotion () {
    Amimal.emotion = 'happy';
  }
  
  play() {
    this.happyEmotion();
  }
  
  eat(food: number) {
     this.energyUp(food);
     this.happyEmotion();
  }
}

const dog = Animal.makeAnimal('dog', 'sery', 'female');

getter 와 setter

  • getter와 setter를 사용하면 조금 더 다양한 연산을 할 수 있으며, 전달된 인자가 정확한지에 대해서 유요성 검사를 할 수 있다.
class User {
  constructor(private name: string, private age: number) {
    this.name = name;
    this.age = age;
  }
  
  get userInfo(): string {
    return `name: ${this.name} , age: ${this.age}`
  }
  
  get age(): number {
    return this.age;
  }
  
 set age(num: number) {
    if (num < 0) {
      throw Error('error')
    }
    this.age = num;
  }
}

const user = new User('sara', 30);
console.log(user.userInfo) // name: sara , age: 30
user.age = 20;
console.log(user.age) // 20

interface

  • class와 상호작용하기 위한 규약을 정의하는 것이다.
  • interface를 사용할 때 implements라는 키워드랄 사용해서 class를 구현한다.
  • interface로 정의한 규약을 class로 구현해야한다.
type IOS = {
  serialNumber: string
}

interface PhoneIOS {
  makePhone(serialNumber: string):IOS 
}

class Phone implements PhoneIOS {
  constroctor(private serialNumber: string) {
    this.serialNumber = serialNumber
  }
  
  makePhone(serialNumber: string):IOS {
    return { serialNumber: string }
  }
}

composition

  • 각각의 기능을 클래스로 만들어두어 필요한 기능을 외부에서 주입받아 가져다 쓰는 것을 말한다.
  • 클래스 간의 상호작용을 하는 경우 interface를 통해 상호작용하는 것이 좋다.

abstract class

  • 상속 클래스를 이용할 때 특정 기능만 자식 클래스에서 달라진다면 Abstact class를 만들어 볼 수 있다.
  • 클래스 앞에 abstract라는 키워드를 사용하면 해당 클래스로 자체 오브젝트를 생성할 수 없다.
profile
개발 노트

0개의 댓글