
절차지향적 프로그래밍이란?
객체지향적 프로그래밍이란?
데이터들과 행동을 할수있는 함수로 구성되어있다.서로 관련있는 데이터와 함수들을 한 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를 통해 상호작용을 해야 한다.