코드에서 반복되는 디자인 문제를 해결하기 위해 사용자 지정할 수 있는 패턴을 미리 정해둔 것입니다.
실제로 복사하여 붙여넣을 수 있는 알고리즘과 다르게 디자인 패턴은 프로그램에 복사 할 수 없기 때문에
자신의 프로그램 현실에 맞는 솔루션을 구현할 필요가 있습니다.
c++로 주로 개발하던 4명 프로그래머는 계속해서 직면하는 프로그래밍적 반복적인 문제를 해결하기 위해 다른 접근 방식을 갖는것의 생성 패턴, 객체 생성의 구조적 패턴, 서로 관련되어있는 패턴등에 따라 디자인 패턴을 분류하기 시작하였습니다.
이를 통해 객체 지향 설계의 다양한 문제를 해결하는 23개의 패턴을 선보였으며 이는 프로그래밍 분야에서 매우 인기를 얻기 시작했고, 네 명의 저자의 긴 이름으로 인해 우리는 이 책을 4인 1조의 책 이라고 부르기 시작해
GOF책 으로 축약 되었습니다.
Creational patterns
Structural Patterns
Behavioral Patterns
싱글톤은 클래스가 하나의 인스턴스
만 갖도록 하는 동시에 이 인스턴스에 대한 전역 액세스 지점을 제공
하는 생성 디자인 패턴입니다.
class Settings{
static instance: Settings;
public readonly mode = 'dark';
private constructor(){
// 생성자를 비공개로 만들어 인스턴스화 할 수 없도록!
}
static getInstance(): Settings{
//인스턴스가 이미 생성되었는지 확인하고 없는 경우에만 새로 생성한다
if(!Settings.instance){
Settings.instance = new Settings();
}
return Settings.instance;
}
}
const settings = Settings.getInstance
자바스크립트는 객체 특성상 단순히 전역 객체를 생성함으로써 위 패턴과 동일한 모든 기능을 구현할 수 있다.
const settings = {
dark: 'true'
}
코드를 클래스에 종속시키지 않고 기존 개체를 복사
할 수 있는 생성 디자인 패턴입니다.
class Animal{}
// class inheritance
class Dog extends Animal {}
class Cat extends Animal {}
이러한 상속을 통한 프로그래밍의 가장 큰 문제점은 복잡도가 높아질 수 있다는 것이다.
하지만 이 문제를 해결할 수 있는 대체제로 프로토타입 패턴이 있습니다.
프로토타입 형태의 프로그래밍은 상속보다 훨씬 단순하기 표현 될 수 있습니다.
특히, 프로토타입언어라 불리는 자바스크립트 에서는 더욱이 그렇습니다.
const zombie = {
eatBrains(){
return 'yum 🧠`
}
}
const chad = Object.create(zombie, {name: {value: 'chad'}});
console.log(chad) // {name: 'chad'}a
chad.eatBrains(); // 'yum 🧠'
// console에는 나오지 않던 메소드가 출력된다.
// 이는 자바스크립트의 프로토타입 체인이 있기 때문 가능한 일
// 아래처럼 proto를 가져오면 eatBrains라는 메소드를 가져올 수 있지만
// 정석인 방법은 getPrototypeOf 메소드를 사용하는 것!
chad.__proto__; // {eatBrains: f}
Object.getPrototypeOf(chad)
// 프로토타입 확장하기
Array.prototype.bad = function(){
console.log('im bad')
}
[].bad() // im bad
복잡한 객체를 단계별로 구성할 수 있는 창작 디자인 패턴으로, 패턴을 사용하면 동일한 구성 코드를 사용
하여 객체의 다양한 유형과 표현을 생성
할 수 있습니다.
class HotDog{
constructor(
public bun: string,
public ketchup: boolean,
public mustard: boolean,
public kraut: boolean
){}
}
addKetchup(){
this.ketchup = true;
// this 를 리턴해줌으로써 메소드체이닝이 가능해진다.
return this;
}
addMustard(){
this.mustard = true;
return this;
}
addKraut(){
this.kraut = true;
return this;
}
const myLunch = new HotDog('wheat', false, true, true)
// method chaining
myLunch
.addKetchup()
.addMustard()
.addKraut();
슈퍼클래스에서 객체를 생성하기 위한 인터페이스를 제공하지만 서브클래스가 생성될 객체의 유형을 변경
할 수 있도록 하는 생성 디자인 패턴입니다.
class IOSButton { }
class AndroidButton { }
const button1 = os === 'ios' ? new IOSButton() : new AndroidButton();
const button2 = os === 'ios' ? new IOSButton() : new AndroidButton();
class ButtonFactory{
createButton(os:string):IOSButton | AndroidButton {
if(os === 'ios'){
return new IOSButton();
} else{
return new AndroidButton();
}
}
}
const factory = new ButtonFactory();
// smart object creation
const btn1 = factory.createButton(os);
const btn2 = factory.createButton(os);
라이브러리, 프레임워크 또는 기타 복잡한 클래스 집합에 대한 단순화된 인터페이스를 제공
하는 구조적 디자인 패턴, facade 패턴의 대표적인 예로 제이쿼리를 들 수 있다.
class PlumbingSystem{
setPressure(v: number){}
turnOn(){}
turnOff(){}
}
class ElectricalSystem{
setVoltage(v: number){}
turnOn(){}
turnOff(){}
}
class House{
private plumbing = new PlumbingSystem();
private electrical = new ElectricalSystem();
public turnOnSystems(){
this.electrical.setVoltage(120);
this.electrical,turnOn();
this.plumbing.setPressure(500);
this.plumbing.turnOn();
}
public shutDown(){
this.plumbing.turnOff();
this.electrical.turnOff();
}
// ugly details hidden
const client = new House();
client.turnOnSystems();
client.shutDown();
}
다른 개체에 대한 대체 또는 자리 표시자를 제공할 수 있는 구조적 디자인 패턴입니다. 프록시는 원래 개체에 대한 액세스를 제어하므로 요청이 원래 개체에 전달되기 전이나 후에 수행
할 수 있습니다.
const original = {name: 'jeff'}
const reactive = new Proxy(original, {
get(target, key){
console.log('Tracking:', key);
return target[key];
},
set(target, key, value){
console.log('updating UI...');
return Reflect.set(target, key, value);
},
});
reactive.name; //logs 'tracking name'
reactive.name = 'bob' //logs 'updating UI...'
기본 표현(목록, 스택, 트리 등)을 노출하지 않고 컬렉션의 요소를 순회
할 수 있는 동작 디자인 패턴입니다.
const card = ['apple', 'banana', 'orange'];
for (const item of cart){
console.log(item)
}
function range(start:number, end:number, step=1){
return{
[Symbol.iterator](){
return this;
},
next(){
if(start<end){
start = start+step;
return {value: start, done: false};
}
return {done: true, value: end};
}
}
}
for(const n of range(0,100,5)){
console.log(n);
}
관찰하는 개체에 발생하는 모든 이벤트
에 대해 여러 개체에 알리는 구독 메커니즘
을 정의할 수 있는 동작 디자인 패턴입니다. (one to many relationship)
import {Subject} from 'rxjs'
const news = new Subject();
const tv1 = news.subscribe(v => console.log(v + 'via Den TV'));
const tv2 = news.subscribe(v => console.log(v + 'via Batcave TV'));
const tv3 = news.subscribe(v => console.log(v + 'via Airport TV'));
news.next('Breaking news: ');
news.next('The war is over');
개체 간의 혼란스러운 종속성을 줄일 수 있는 행동 디자인 패턴
입니다. 패턴은 개체 간의 직접 통신을 제한하고 중재자 개체를 통해서만 협력
하도록 합니다.
class Airplain{
land(){}
}
class Runway {
clear: boolean;
}
class Tower {
clearForLanding(runway: Runway, plain: Airplane){
if(runway.clear){
console.log(`Plane ${plane} is clear for landing`);
}
}
}
const runway25A = new Runway();
const runway25B = new Runway();
const runway7 = new Runway();
const a = new Airplane();
const b = new Airplane();
const c = new Airplane();
const tower = new Tower();
tower.clearForLanding(runway25A, a)
Mediator
의 대표적예로 express middleware
가 있습니다.
import express from 'express'
const app = express();
function logger(req, res, next){
console.log('Request Type:', req.method)
next()
}
app.use(logger);
app.get('/', (req, res)=>{
res.send('Hello World');
});
내부 상태가 변경될 때 객체가 동작을 변경
할 수 있도록 하는 동작 디자인 패턴입니다.
객체가 클래스를 변경한 것처럼 보입니다.
// switch hell
class Human{
think(mood){
switch(mood){
case 'happy':
return 'I am happy';
case 'sad' :
return 'I am sad';
default:
return 'I am neutral';
}
}
// Same method, different outcome
class HappyState implements State{
think(){
return 'I am happy';
}
}
class SadState implements State{
think(){
return 'I am sad';
}
}
class Human{
state: State;
constructor(){
this.state = new happyState();
}
think(){
return this.state.think();
}
changeState(state){
this.state = state;
}
}
https://www.youtube.com/watch?v=tv-_1er1mWI
https://refactoring.guru/design-patterns/catalog
글 잘 읽었습니다~! 정리도 잘하시고 예제 코드들도 좋네요~!