디자인 패턴은 반복되는 문제에 대한 해결책이며, 특정 문제를 해결하는 방법에 대한 지침이다.
디자인 패턴은 문제의 해결책
이며, 문제를 찾는 해결책은 아니다. (...?)
객체 또는 관련된 객체 그룹을
인스턴스화
하는 방법에 초점을 맞춘다.
심플 팩토리는 클라이언트에게 인스턴스화 로직을 노출하지 않고 클라이언트용 인스턴스를 생성한다.
interface Door {
getWidth(): number;
getHeight(): number;
}
class WoodenDoor implements Door {
protected width: number;
protected height: number;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
}
getWidth(): number {
return this.width;
}
getHeight(): number {
return this.height;
}
}
class DoorFactory {
public static makeDoor(width: number, height: number): Door {
return new WoodenDoor(width, height);
}
}
// 위와 같은 팩토리가 있을 때, 클라이언트에서 인스턴스를 생성하는 법은 아래와 같이 하면 된다.
const door = DoorFatory.makeDoor(100,100);
👍 객체를 생성할 때, 일부 로직을 포함해야 할 경우 위와 같은 팩토리 패턴을 사용하면 좋다.
예를 들어,makeDoor
에서 width와 height로 계산 로직이 들어갈 수도 있다.
자식 클래스에게 인스턴스화 로직을 위임하는 방식이다.
이게 무슨 소리인고하니, 예를 들어
개발관련 면접관
이 있을 것이고,소통관련 면접관
이 있을 것이다.이처럼, 여러종류의
면접관이 많을 것인데, 이것은 면접자에 따라 달라진다.
(클라이언트에서 사용될 때(런타임)에 따라 특정 클래스에서 필요한 인스턴스를 받아야 한다.
(팩토리 메소드, 해당 글을 보고 이해했다)
면접관 Class
이를 위해서, 면접관 Class에서 종류에 따라 필요한 면접관을 할당(인스턴스화)
하려면 모든 조건에 따라 분기처리를 해주어야 한다. (이는 개방/폐쇄 원칙
에 좋지 않다)
👍 필요한 인스턴스가 런타임에 동적으로 결정될 때 유용하다.
구체적인 내용을 지정하지 않고, 관련된 것들을 그룹화한다.
interface Door {
getDesc() : void;
}
class ADoor implements Door {
getDesc() {
console.log("ADoor");
}
}
class BDoor implements Door {
getDesc() {
console.log("BDoor");
}
}
----
interface DoorMan {
fix() : void;
}
class ADoorMan implements DoorMan {
fix() {
console.log('난 15달러');
}
}
class BDoorMan implements DoorMan {
fix() {
console.log('난 4달라');
}
}
---
interface DoorFactory {
getDesc(): Door;
fix(): DoorMan;
}
class ADoorFactory implements DoorFactory {
getDesc(): Door {
return new ADoor();
}
fix(): DoorMan {
return new ADoorMan();
}
}
class BDoorFactory implements DoorFactory {
getDesc(): Door {
return new BDoor();
}
fix(): DoorMan {
return new BDoorMan();
}
}
이처럼, Factory안에서는 구현내용없이, 관련된 내용을 그룹화하고 return하는 내용밖에 없다.
👍 상호 의존성이 있고, 복잡한 생성로직이 있는 경우 유용하다.
// 생성자를 이용한 방식
class Burger {
protected size: number;
protected cheese: boolean = false;
protected pepperoni: boolean = false;
protected lettuce: boolean = false;
protected tomato: boolean = false;
constructor(builder: BurgerBuilder) {
this.size = builder.size;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.lettuce = builder.lettuce;
this.tomato = builder.tomato;
}
}
class BurgerBuilder {
public size: number;
public cheese: boolean = false;
public pepperoni: boolean = false;
public lettuce: boolean = false;
public tomato: boolean = false;
constructor(size: number) {
this.size = size;
}
addPepperoni(): BurgerBuilder {
this.pepperoni = true;
return this;
}
addLettuce(): BurgerBuilder {
this.lettuce = true;
return this;
}
addCheese(): BurgerBuilder {
this.cheese = true;
return this;
}
addTomato(): BurgerBuilder {
this.tomato = true;
return this;
}
build(): Burger {
return new Burger(this);
}
}
// 활용
const burger = new BurgerBuilder(14)
.addPepperoni()
.addLettuce()
.addTomato()
.build();
👍 객체의 생성이 여러단계에 걸쳐야 할 때 유용하다.
객체를 복사하여, 새로운 객체를 생성한다.
Object.create
로 간단하게 수행가능하다.const original: Sheep = new Sheep("A");
// original
// name : "A"
// category : "sheep"
const clone: Sheep = Object.create(original);
clone.setName("B")
// clone
// name : "B"
// category : "sheep"
👍 기존 객체와 유사한 객체가 필요하거나, 생성 비용이 많이 드는 경우 유용하다.
특정 클래스의 객체가 한번만 생성되도록 한다.
⚠️ 싱글톤은 안티패턴으로 분류된다. 일부사례에서 유용하긴 하나, 주의해서 사용해야 한다.
생성자
, 복제
, 확장
을 비활성화
하고, 특정 메소드로만 인스턴스 get이 가능하다.// 대통령을 예시로 들어보겠습니다. (대통령은 1명 뿐이니)
class President {
private static instance: President;
private constructor() {}
private clone(){}
private wakeup(){}
public static getInstance: President {
if(!President.instance) {
President.instance = new Presiden();
}
return President.instance;
}
}
const president1: President = President.getInstance();
const president2: President = President.getInstance();
console.log(president1 === president2); // true
구조패턴은 다음편에...