{
type CoffeeCup = {
shots: number;
hasMilk: boolean;
};
*// interface - 추상화
// public 한 멤버변수와 메소드만 선언 가능*
interface CoffeeMakerA {
makeCoffee(shots: number): CoffeeCup;
}
interface CoffeeMakerB {
makeCoffee(shots: number): CoffeeCup;
clean(): void;
}
*// 추상화로 만들어진 인터페이스나 부모 클래스에 추상화 하고자 하는 기능들이
// 선언되어져 있어야 한다.*
class CoffeeMaker {
private static BEANS_GRANS_PER_SHOT = 7; *// static 변수는 변경 불가*
private coffeeBeans: number = 0;
private constructor(coffeeBeans: number) {
this.coffeeBeans = coffeeBeans;
}
static makeMachine(coffeeBeans: number) {
return new CoffeeMaker(coffeeBeans);
}
public fillCoffeeBeans(beans: number) {
if (beans < 0) {
throw new Error('beans not enoughf');
}
this.coffeeBeans += beans;
}
public makeCoffee(shots: number): CoffeeCup {
if (this.coffeeBeans < shots * CoffeeMaker.BEANS_GRANS_PER_SHOT) {
throw new Error('Not enough coffee beans!');
}
this.coffeeBeans -= shots * CoffeeMaker.BEANS_GRANS_PER_SHOT;
return {
shots: shots,
hasMilk: false,
}
}
public clean() {
console.log("Coffee Cleaning~...✨");
}
}
class CoffeeStoreA {
constructor(private machine: CoffeeMakerA) {
machine.makeCoffee(2);
}
}
class CoffeeStoreB {
constructor(private machine: CoffeeMakerB) {
machine.makeCoffee(2);
machine.clean();
}
}
const maker2: CoffeeMakerA = CoffeeMaker.makeMachine(34);
console.log(maker2.makeCoffee(2));
}
[ 추상화 - abstraction ]
추상화란, 외부에서 어떤 형태로, 공통적으로 어떻게 이 클래스를 이용하게 할 것인가.. 이걸 고민하는 단계라 할 수 있다.
대표적으로 두 가지 방법이 있는데
첫 번째로 메인 클래스에 부모 클래스를 상속받아 부모 클래스에 정의된 기능들을 추출하는 방법, 두 번째로 메인 클래스에 인터페이스를 상속받아 인터페이스에 정의된 기능들을 추출하는 방법이 있다.
이렇게 추상화가 되면 사용자는 추상화된 기능만 사용할 수 있기 때문에 보다 직관적이게 기능을 사용할 수 있다.
단순한 추상화
단순하게는 캡슐화를 통해 추상화를 할 수도 있지만 말만 추상화 일 뿐 실질적으로는 public 과 private 으로 외부에 노출할 기능을 보이고 숨기는 정도가 전부일 것이다.
헷갈리는 개념 (캡슐화와 추상화) = (정보 은닉과 추상화)
추상화는 클래스를 간편하고 가독성 있게 사용하기 위해 클래스를 간단하게(심플) 만드는 단계이고, 캡슐화는 클래스를 만들 때 외부에서 클래스 내부 변수 및 함수에 함부로 접근하지 못하게 막고 필요한 기능은 오픈하는 역할이다.