회사일이 바빠서 ㅠㅠ
평일에 JS공부랑 알고리즘 풀고, 회사일을 조금 하니 시간이 없었다...
회사에서 TS를 안쓰니 우선순위가 밀리는 것 같다.
그래서 주말에 하려고 한다!
객체들을 컨셉으로 프로그래밍을 해나가는 방식.
프로그램을 객체로 정의해, 객체들끼리 소통하도록 디자인.
한곳에서 문제가 생기면 관련 Obj만 수정, 재사용 가능!
확장성도 새 Obj를 만들면 되므로 좋다.
-> 생산성, 높은퀄리티, Faster
객체(object)란 간단히 이야기하자면 실생활에서 우리가 인식할 수 있는 사물로 설명할 수 있다.
이러한 객체의 상태(state)와 행동(behavior)을 구체화하는 형태의 프로그래밍이 바로 객체 지향 프로그래밍.
Error Exception 같이 조금 추상적인 것도 Obj 가능 -> 명사형으로 이름!
이때 객체를 만들어 내기 위한 설계도와 같은 개념을 클래스(class)라고 한다.
클래스는 객체의 상태를 나타내는 필드(field)와 객체의 행동을 나타내는 메소드(method)로 구성된다.
즉, 필드(field)란 클래스에 포함된 변수(variable)를 의한다.
메소드(method)란 어떠한 특정 작업을 수행하기 위한 명령문의 집합.
클래스에 데이터를 넣어서 Obj인스턴스를 만든다!
type Coffeecup = {
shots: number;
hasMilk: boolean;
}
Class CoffeeMachine {
static BEANS_PER_SHOT: number = 5; // class lv
coffeBeans: number = 0; // instance lv
constructor(coffeeBeans: number) {
this.coffeeBeans = coffeeBeans
}
static makeMachine(coffeeBeans: number): CoffeeMachine {
return new CoffeeMachine(coffeeBeans
}
makeCoffee(shots: number): Coffeecup {
if (this.coffeeBeans < shots * CoffeeMachine.BEANS_PER_SHOT) {
throw new Error();
}
this.coffeeBeans -= shots * CoffeeMachine.BEANS_PER_SHOT;
return {
shots,
hasMilk: false
}
}
}
const maker = new CoffeeMachine(33);
const maker2 = CoffeeMachine.makeMachine(3);
type Coffeecup = {
shots: number;
hasMilk: boolean;
}
Class CoffeeMachine {
private static BEANS_PER_SHOT: number = 5; // class lv
private coffeBeans: number = 0; // instance lv
private constructor(coffeeBeans: number) {
this.coffeeBeans = coffeeBeans
}
static makeMachine(coffeeBeans: number): CoffeeMachine {
return new CoffeeMachine(coffeeBeans)
}
fillCoffeeBeans(beans: number) {
if (beans < 0) {
throw new Error();
}
this.coffeeBeans += beans;
}
makeCoffee(shots: number): Coffeecup {
if (this.coffeeBeans < shots * CoffeeMachine.BEANS_PER_SHOT) {
throw new Error();
}
this.coffeeBeans -= shots * CoffeeMachine.BEANS_PER_SHOT;
return {
shots,
hasMilk: false
}
}
}
const maker = new CoffeeMachine(33);
maker.fillCoffeeBeans(33);
class User {
get fullName(): string{
return `&{fistName}${lastName}`;
}
private internalAge = 4;
get age(): number {
return this.internalAge;
}
set age(num:number) {
this.internalAge = num;
}
constructor(private firstName: stinrg, private lastName: string) {
}
// 이러면 firstname, lastname으로 설정되고 this의 , private로 설정된다!
}
user.age = 6;
어떤 Obj에 대한 내부구조를 알 필요없이 사용하도록 하는 것.
type Coffeecup = {
shots: number;
hasMilk: boolean;
}
interfact CoffeeMaker {
makeCoffee(shots: number): CoffeeCupt;
}
interfact CommercialCoffeeMaker {
makeCoffee(shots: number): CoffeeCupt;
fillCoffeeBeans(shots: number): void;
clean(): void;
}
Class CoffeeMachine implements CoffeeMaker, CommercialCoffeeMaker{
private static BEANS_PER_SHOT: number = 5; // class lv
private coffeBeans: number = 0; // instance lv
private constructor(coffeeBeans: number) {
this.coffeeBeans = coffeeBeans
}
static makeMachine(coffeeBeans: number): CoffeeMachine {
return new CoffeeMachine(coffeeBeans)
}
clean() {
console.log('cleaning');
}
private fillCoffeeBeans(beans: number) {
if (beans < 0) {
throw new Error();
}
this.coffeeBeans += beans;
}
private preheat(): void {
console.log('heat');
}
private extract(shots:number): CoffeeCup {
return {
shots,
isHeat: false
}
}
grindBeans(shots: number) {
if (this.coffeeBeans < shots * CoffeeMachine.BEANS_PER_SHOT) {
throw new Error();
}
this.coffeeBeans -= shots * CoffeeMachine.BEANS_PER_SHOT;
}
makeCoffee(shots: number): Coffeecup {
this.grindBeans(shots);
this.preheat();
return this.extract(shots);
}
}
const maker: CoffeeMachine = CoffeeMachine.makeMachine(33);
const maker2: CommercialCoffeeMaker = CoffeeMachine.makeMachine(33); // 인터페이스 따름
maker.fillCoffeeBeans(33);
기존 Obj를 활용하는것을 상속이라 한다. -> 재사용성 good
extends : 상속을 위해 사용한다. 부모 클래스에서 private을 사용하면 상속이 되지 않으니 public이나 protected로 바꾸어 주어야 한다.
super : 자식클래스에서 super. 으로 가져와 사용할 수 있다.
type Coffeecup = {
shots: number;
hasMilk: boolean;
}
interfact CoffeeMaker {
makeCoffee(shots: number): CoffeeCupt;
}
Class CoffeeMachine implements CoffeeMaker{
static BEANS_PER_SHOT: number = 5; // class lv
coffeBeans: number = 0; // instance lv
constructor(coffeeBeans: number) {
this.coffeeBeans = coffeeBeans
}
static makeMachine(coffeeBeans: number): CoffeeMachine {
return new CoffeeMachine(coffeeBeans)
}
clean() {
console.log('cleaning');
}
fillCoffeeBeans(beans: number) {
if (beans < 0) {
throw new Error();
}
this.coffeeBeans += beans;
}
preheat(): void {
console.log('heat');
}
extract(shots:number): CoffeeCup {
return {
shots,
isHeat: false
}
}
grindBeans(shots: number) {
if (this.coffeeBeans < shots * CoffeeMachine.BEANS_PER_SHOT) {
throw new Error();
}
this.coffeeBeans -= shots * CoffeeMachine.BEANS_PER_SHOT;
}
makeCoffee(shots: number): Coffeecup {
this.grindBeans(shots);
this.preheat();
return this.extract(shots);
}
}
class CaffeLatteMachine extends CoffeeMachine { --> 생성자가 private일떄느 안됨
constructor(beans: number, public readonly serialNumber: string) {
super(number)
} -> 자식 클래스의 생성자는 꼭 super호출
private steamMilk(): void {
}
makeCoffee(shots:number): CoffeeCup {
const coffee = super.makeCoffee(shots) //부모 함수호출
this.steamMilk();
return {
...coffee,
hasMilk: true,
}
}
}
const maker: CoffeeMachine = CoffeeMachine.makeMachine(33);
maker.fillCoffeeBeans(33);
type Coffeecup = {
shots: number;
hasMilk?: boolean;
hasSugar?: boolean;
}
interfact CoffeeMaker {
makeCoffee(shots: number): CoffeeCupt;
}
Class CoffeeMachine implements CoffeeMaker{
static BEANS_PER_SHOT: number = 5; // class lv
coffeBeans: number = 0; // instance lv
constructor(coffeeBeans: number) {
this.coffeeBeans = coffeeBeans
}
static makeMachine(coffeeBeans: number): CoffeeMachine {
return new CoffeeMachine(coffeeBeans)
}
clean() {
console.log('cleaning');
}
fillCoffeeBeans(beans: number) {
if (beans < 0) {
throw new Error();
}
this.coffeeBeans += beans;
}
preheat(): void {
console.log('heat');
}
extract(shots:number): CoffeeCup {
return {
shots,
isHeat: false
}
}
grindBeans(shots: number) {
if (this.coffeeBeans < shots * CoffeeMachine.BEANS_PER_SHOT) {
throw new Error();
}
this.coffeeBeans -= shots * CoffeeMachine.BEANS_PER_SHOT;
}
makeCoffee(shots: number): Coffeecup {
this.grindBeans(shots);
this.preheat();
return this.extract(shots);
}
}
class CaffeLatteMachine extends CoffeeMachine { --> 생성자가 private일떄느 안됨
constructor(beans: number, public readonly serialNumber: string) {
super(number)
} -> 자식 클래스의 생성자는 꼭 super호출
private steamMilk(): void {
}
makeCoffee(shots:number): CoffeeCup {
const coffee = super.makeCoffee(shots) //부모 함수호출
this.steamMilk();
return {
...coffee,
hasMilk: true,
}
}
}
class SweetCoffeeMaker extends CoffeMachine {
makeCoffee(shots: number) :CoffeeCup {
const coffee = super.makeCoffee(shots);
return {
...coffee,
hasSugar: true,
}
}
} -> 다양성 한 클래스로 다양한 클래스가 나옴,
const maker: CoffeeMachine = CoffeeMachine.makeMachine(33);
maker.fillCoffeeBeans(33);
const machine: CoffeeMaker[] = [
new CoffeeMachine(6),
new CaffeeLatteeMachine(6, '1'),
new SweetCoffeeMaker(15),
new CoffeeMachine(12),
] - > Inplements 를 상속받아 인터페이스 배열
makeCoffee 만 호출 가능 (interface)
machine.forEach((machine) => {
machine.makeCoffee(1)
})
CoffeeMachine 한 클래스로 라떼, 단 커피 등등 여러가지를 만들 수 있다.
내부적으로 구현된 다양한 클래스들이 한 인터페이스 혹은 동일한 부모를 받았을 때, 구별않고 다양한 기능이지만 공통된 API호출이 가능하다. , 가독성 및 추상화 증대
관계가 복잡해진다.
부모의 행동을 수정하면 부모를 상속하는 모든 곳에 영향을 미친다.
또한 TS에서는 한가지 이상의 부모를 상속하지 못한다.
ex 달달한 카페라떼 머신은 뭘 상속해야 할까, 흑설탕은?
커피머신 > 카페라떼 머신(우유), 달달한 머신(설탕) ->
해결 > composition