절차지향적 프로그래밍이란?
객체지향적 프로그래밍이란?
데이터
들과 행동을 할수있는 함수
로 구성되어있다.서로 관련있는 데이터와 함수들을 한 Object에 담아두고 외부에 보일 필요없는 데이터들을 숨겨두는 것이 캡슐화
추상화를 통해 외부에서는 내부에 복잡한 로직들을 신경쓰지 않고 외부 인터페이스 함수를 이용해 Object를 사용하는 것
자식 클래스가 부모 클래스의 데이터나 함수를 그대로 받아서 사용할수 있는 것
IS-A
관계: 클래스들 사이의 포함 관계를 의미하며, 한 클래스 A가 다른 클래스 B의 서브 클래스임을 이야기 한다.
상속을 통해 만들어진 Object들은 어떤 타입인지 상관하지 않고 공통된 함수를 통해 접근할수 있다.
static
으로 정의static
은 멤버변수나 함수에 적용가능static
키워드를 붙여 외부에서도 클래스를 만들지 않고도 사용할수 있게 된다.abstract
키워드를 붙임protected
접근지정자를 지정 abstract
키워드가 붙은 함수는 상속하는 클래스에서 항상 따로 구현해주어야 함abstract
클래스에서 의도한대로 최대한 abstract
으로 지정된 함수들만 오버라이딩 해야한다.abstract class AbstractClass {
//... 공통된 기능들;
// 상속한 클래스마다 달라져야하는 기능은 abstract 함수로 생성
protected abstract absFunc();
}
interface
는 구현사항이 들어갈수 없고 속성과 행동의 타입만 정의함abstract class
는 공통적으로 필요한 로직을 구현할 수 있음class
를 만들때 외부에서 접근할수있는 것은 무엇인지 내부적으로만 갖고있어야 되는것이 무엇인지 결정할 수 있다.private
로 숨기고 외부의 함수를 통해 상태를 변경할 수 있게 코드를 작성/* static 키워드가 붙은 Object를 만들수있는 함수를 제공한다면
생성자함수로 만드는것을 금지한다는말과 같다.
constructor()에 private로 만들어서 항상 static 함수를 사용할수있도록 권장 */
class TestClass {
pricate data: number = 0;
prviate constructor(data: number) {
this.data = data;
}
static makeClass(data: number) {
return new TestClass(data);
}
}
getter
, setter
은 일반 변수처럼 사용가능하지만 어떠한 계산을 해야할때 유용하게 사용가능class User {
private internalAge = 5;
get age(): number {
return this.internalAge;
}
set age(num: number) {
if (num < 0) {
throw new Error('is not valid age'); // 유효성 검사
}
this.internalAge = num;
}
}
const user = new User();
user.age = 6; // setter 호출
console.log(user.age); // 6
encapsulation
과 interface
를 통해 추상화가 가능하다.class CoffeeMachine {
private grindeBenas(shots: number) {
...logic
};
private preheat(): void {
...logic
};
private extract(shots: number) {
...logic
};
makeCoffee(sthos: number) {
this.grindBeans(shots);
this.preheat();
return this.extract(shots);
}
}
const coffee = new CoffeeMachine();
coffee.grindBeans() // error 찾지못함
coffee.preheat() // error
coffee.extract() // error
coffee.makeCoffee(2);
interface
란 요구사항을 명시해놓은 계약서와 같다.interface
를 구현하는 class
에서는 interface
에 규약된 모든 함수를 구현해야한다.interface
를 이용하면 내가 얼마만큼의 행동을 허용할것인지 결정할 수 있다.class
보다 좁은 범위의 interface
에 규약된 함수들만 접근 가능 class
에 여러 interface
를 지정할 수 있다.class
에 다른 복잡한 기능을 알필요 없고 interface
만 어떻게 사용하면 되는지만 알면 된다.interface Contract {
otherFunc(num: number): otherObj;
}
class otherClass implements Contract {
otherFunc(num: number): otherObj {
...logic
}
otherOtherFunc(str: string): void {
...logic
}
}
const class1: otherClass = new otherClass();
class1.otherFunc(2);
class1.otherOtherFunc('123');
const class2: Contract = new otherClass(); // interface로 타입을 제한
class2.otherFunc(2);
class2.otherOtherFunc('123'); // error
class Child extends Parent {
constructor(...) {
super(...); // Parent Class 생성자함수
}
// Parent Class 함수 와 데이터 이용 가능
}
class Child1 extends Parent {
commonFunc(num: number): void {
super.commonFunc(num);
console.log('child func');
}
}
const childs: Parent[] = [
new Child1,
new Child2,
new Child3,
];
childs.forEach(child => {
console.log('----------------');
child.commonFunc(2);
})
composition
을 이용해서 필요한 기능을 재사용함class
와 class
들 사이의 관계를 짓는것은 좋지 않다.composition class
를 수정하면 그와 관련된 모든 class
들을 수정해야 한다.class
들 사이의 서로 상호작용하는 경우에 class
자신을 노출하는 것이 아닌 interface
를 통해 상호작용을 해야 한다.