Home 타입스크립트 OOP 객체지향
Post
Cancel

타입스크립트 OOP 객체지향

객체지향이란?


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

장점

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

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

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

객체지향 요소


캡슐화(Encapsulation)

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

정보 은닉(Infomation Hiding)

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

constructor

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

public

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

private

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

protected

  • 다른 클래스에게는 노출되지 않지만, 상속받은 자식 클래스에게는 노출되는 것이다.
  • 외부에서 접근할 수 없고 상속받은 class만이 접근이 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 함수를 사용하면서 외부에서는 에너지나 감정이 변화하는 함수를 이해하지 않아도 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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를 이용해 전달해 주어야 한다.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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();

다형성

  • 상속을 통해서 만들어진 자식 클래스들의 종류와 상관없이 부모 클래스에 정의된 함수를 호출할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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 이름으로 접근할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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를 사용하면 조금 더 다양한 연산을 할 수 있으며, 전달된 인자가 정확한지에 대해서 유요성 검사를 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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로 구현해야한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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라는 키워드를 사용하면 해당 클래스로 자체 오브젝트를 생성할 수 없다.
This post is licensed under CC BY 4.0 by the author.