GOF 대표적인 10 가지 Design patterns
What is design pattern ❓❗️
코드에서 반복되는 디자인 문제를 해결하기 위해 사용자 지정할 수 있는 패턴을 미리 정해둔 것입니다.
실제로 복사하여 붙여넣을 수 있는 알고리즘과 다르게 디자인 패턴은 프로그램에 복사 할 수 없기 때문에
자신의 프로그램 현실에 맞는 솔루션을 구현할 필요가 있습니다.
패턴의 역사 Gang of Four 👬👬
c++로 주로 개발하던 4명 프로그래머는 계속해서 직면하는 프로그래밍적 반복적인 문제를 해결하기 위해 다른 접근 방식을 갖는것의 생성 패턴, 객체 생성의 구조적 패턴, 서로 관련되어있는 패턴등에 따라 디자인 패턴을 분류하기 시작하였습니다.
이를 통해 객체 지향 설계의 다양한 문제를 해결하는 23개의 패턴을 선보였으며 이는 프로그래밍 분야에서 매우 인기를 얻기 시작했고, 네 명의 저자의 긴 이름으로 인해 우리는 이 책을 4인 1조의 책 이라고 부르기 시작해
GOF책 으로 축약 되었습니다.
The Catalog of Design Patterns
Creational patterns
- 기존 코드의 유연성과 재사용을 증가시키는 다양한 객체 생성 메커니즘을 제공
Structural Patterns
- 구조를 유연하고 효율적으로 유지하면서 개체와 클래스를 더 큰 구조로 어셈블하는 방법을 설명
Behavioral Patterns
- 알고리즘 및 객체 간의 책임 할당과 관련
Creational patterns 🧤
SINGLETON
싱글톤은 클래스가 하나의 인스턴스
만 갖도록 하는 동시에 이 인스턴스에 대한 전역 액세스 지점을 제공
하는 생성 디자인 패턴입니다.
typescript example
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'
}
PROTOTYPE
코드를 클래스에 종속시키지 않고 기존 개체를 복사
할 수 있는 생성 디자인 패턴입니다.
class Animal{}
// class inheritance
class Dog extends Animal {}
class Cat extends Animal {}
이러한 상속을 통한 프로그래밍의 가장 큰 문제점은 복잡도가 높아질 수 있다는 것이다.
하지만 이 문제를 해결할 수 있는 대체제로 프로토타입 패턴이 있습니다.
프로토타입 형태의 프로그래밍은 상속보다 훨씬 단순하기 표현 될 수 있습니다.
특히, 프로토타입언어라 불리는 자바스크립트 에서는 더욱이 그렇습니다.
typescript example
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
BUILDER
복잡한 객체를 단계별로 구성할 수 있는 창작 디자인 패턴으로, 패턴을 사용하면 동일한 구성 코드를 사용
하여 객체의 다양한 유형과 표현을 생성
할 수 있습니다.
typescript example
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();
FACTORY
슈퍼클래스에서 객체를 생성하기 위한 인터페이스를 제공하지만 서브클래스가 생성될 객체의 유형을 변경
할 수 있도록 하는 생성 디자인 패턴입니다.
typescript example
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);
Structural Patterns
FACADE
라이브러리, 프레임워크 또는 기타 복잡한 클래스 집합에 대한 단순화된 인터페이스를 제공
하는 구조적 디자인 패턴, facade 패턴의 대표적인 예로 제이쿼리를 들 수 있다.
typescript example
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();
}
PROXY
다른 개체에 대한 대체 또는 자리 표시자를 제공할 수 있는 구조적 디자인 패턴입니다. 프록시는 원래 개체에 대한 액세스를 제어하므로 요청이 원래 개체에 전달되기 전이나 후에 수행
할 수 있습니다.
typescript example
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...'
Behavioral Patterns
ITERATOR
기본 표현(목록, 스택, 트리 등)을 노출하지 않고 컬렉션의 요소를 순회
할 수 있는 동작 디자인 패턴입니다.
typescript example
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);
}
OBSERVER
관찰하는 개체에 발생하는 모든 이벤트
에 대해 여러 개체에 알리는 구독 메커니즘
을 정의할 수 있는 동작 디자인 패턴입니다. (one to many relationship)
typescript example
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');
MEDIATOR
개체 간의 혼란스러운 종속성을 줄일 수 있는 행동 디자인 패턴
입니다. 패턴은 개체 간의 직접 통신을 제한하고 중재자 개체를 통해서만 협력
하도록 합니다.
typescript example
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');
});
STATE
내부 상태가 변경될 때 객체가 동작을 변경
할 수 있도록 하는 동작 디자인 패턴입니다.
객체가 클래스를 변경한 것처럼 보입니다.
typescript example
// 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';
}
}
state 패턴
class Human{
state: State;
constructor(){
this.state = new happyState();
}
think(){
return this.state.think();
}
changeState(state){
this.state = state;
}
}
Reference
https://www.youtube.com/watch?v=tv-_1er1mWI
https://refactoring.guru/design-patterns/catalog
Author And Source
이 문제에 관하여(GOF 대표적인 10 가지 Design patterns), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sunhwa508/GOF-대표적인-10-가지-Design-patterns저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)