Design Pattern

Design Patterns

๐Ÿ’๐Ÿปโ€โ™‚๏ธContents

1. Compositeย 

2. Decoratorย 

3. Observe

4. Facade

5. Mediator

Composite Pattern

Composite

๊ฐœ๋ณ„ ๊ฐ์ฒด์™€ ๋ณตํ•ฉ ๊ฐ์ฒด๋“ค์„ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ํŒจํ„ด

Composite

function EquipmentComposition(name) {
  this.equipments = [];
  this.name = name;
}

EquipmentComposition.prototype.add = function(equipment) {
  this.equipments.push(equipment);
};

EquipmentComposition.prototype.getPrice = function() {
  return this.equipments.map(function(equipment) {
    return equipment.getPrice();
  }).reduce(function(a, b) {
    return a + b;
  });
};

function Equipment() {}

Equipment.prototype.getPrice = function() {
  return this.price;
};

composit

Composite

function Equipment() {}

Equipment.prototype.getPrice = function() {
  return this.price;
};

function FloppyDisk() {
  this.name = "Floppy Disk";
  this.price = 70;
}
FloppyDisk.prototype = Object.create(Equipment.prototype);

function HardDrive() {
  this.name = "Hard Drive";
  this.price = 250;
}
HardDrive.prototype = Object.create(Equipment.prototype);

function Memory() {
  this.name = "8gb memomry";
  this.price = 280;
}
Memory.prototype = Object.create(Equipment.prototype);

leaf

Composite

โ—ย Client์—์„œ leaf์™€ Composite๋ฅผ ๊ตฌ๋ถ„ํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ์‰ฝ๋‹ค

ย 

โ—ย left/composite๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ์ผ๊ด€๋œ ๊ณ„์ธต์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

ย 

โ—ย composite์™€ leaf๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋ฏ€๋กœ ์ƒˆ๋กœ์šด ์š”์†Œ๊ฐ€ ์ถ”๊ฐ€๋˜๋”๋ผ๋„ย 

ย  ย ๋ถ€์ˆ˜ํšจ๊ณผ๊ฐ€ ์—†๋‹ค.

ย 

โ—ย jQuery๋ฅผ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ๋กœ ๋“ค ์ˆ˜ ์žˆ๋‹ค..

Decorator Pattern

Decorator

์ƒํ™ฉ์— ๋”ฐ๋ผ ์–ด๋–ค ๊ฐ์ฒด์— ์ฑ…์ž„์„ ๋ง๋ถ™์ด๋Š” ํŒจํ„ด

Decorator

ํด๋ž˜์Šค ์ƒ์†

// ์ปคํ”ผ๋Š” ์—์Šคํ”„๋ ˆ์†Œ๋ถ€ํƒ€ ์‹œ์ž‘... ์Šˆํผํด๋ž˜์Šค๋กœ ์„ ์–ธ
function Espresso() {
  this.cost = 2500;
}


// ์•„๋ฉ”๋ฆฌ์นด๋…ธ, ์นดํŽ˜๋ผ๋–ผ.. ์„œ๋ธŒํด๋ž˜์Šค๋กœ ์„ ์–ธ
function Americano() {
  Espresso.call(this);
  this.cost = (new Espresso()).cost + 500;
  this.water = 250;
}

function CafeLatte() {
  Americano.call(this);
  this.cost = (new Americano()).cost + 500;
  this.milk = 100;
}


console.log(new Espresso());
// { cost: 2500 }
console.log(new Americano());
// { cost: 3000, water: 250 }
console.log(new CafeLatte());
//{ cost: 3500, water: 250, milk: 100 }

Decorator

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ ์šฉ

// ์—์Šคํ”„๋ ˆ์†Œ์— ๋ฌผ์„ ๋„ฃ์ž...
function Water (espresso) {
  espresso.cost = espresso.cost + 500;
  espresso.water = 250;
  return espresso; //ํ•จ์ˆ˜ ์ฒด์ด๋‹
}

// ์—์Šคํ”„๋ ˆ์†Œ์— ์šฐ๋ฅ˜๋ฅผ ๋„ฃ์ž..
function Milk (espresso) {
  espresso.cost = espresso.cost + 500;
  espresso.milk = 100;
  return espresso;
}

var espresso = new Espresso();
// { cost: 2500 }
var americano = Water(new Espresso());
// { cost: 3000, water: 250 }
var cafeLatte = Milk(Water(new Espresso()));
// { cost: 3500, water: 250, milk: 100 }

Decorator

Ghost ์ฝ”๋“œ์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ

// ํŒŒ๋ผ๋งคํ„ฐ๋กœ ๋ฐ›์€ apiMethod ํ•จ์ˆ˜๋ฅผ ๋ฐ›๋Š”๋‹ค.
http = function http(apiMethod) {

    return function apiHandler(req, res, next) {
        // request ๊ฐœ์ฒด๋ฅผ ํ†ตํ•ด ๋„˜์–ด์˜จ ์š”์ฒญ๋ฐ์ดํ„ฐ๋ฅผ ์ •๊ทœํ™” ํ•œ๋‹ค. 
        // body, params, query, files ๋ฅผ object์™€ options ๊ฐ์ฒด์— ๋ชจ์•„ ๋‹ด๋Š”๋‹ค.
        var object = req.body,
            options = _.extend({}, req.files, req.query, req.params, {
                context: {
                    user: (req.user && req.user.id) ? req.user.id : null
                }
            });
        if (_.isEmpty(object)) {
            object = options;
            options = {};
        }

        // ์ •๊ทœํ™”๋œ ์š”์ฒญ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ๋ผ๋ฉ”ํ„ฐ๋กœ ๋„˜์–ด์˜จ apiMethod ํ•จ์ˆ˜์— ๋„˜๊ฒจ์ค€๋‹ค.
        return apiMethod(object, options).tap(function onSuccess(response) {
            // ์‘๋‹ต ํ—ค๋”๋ฅผ ์„ค์ •ํ•œ๋‹ค.
            return addHeaders(apiMethod, req, res, (response || {}));
        }).then(function then(response) {
            // ์‘๋‹ต ๋ฐ”๋””๋ฅผ ์„ค์ •ํ•œ๋‹ค.
            res.json(response || {});
        }).catch(function onAPIError(error) {
            // ์—๋Ÿฌ ์ฒ˜๋ฆฌ
            next(error);
        });
    };
};

Decorator

โ—ย ์ปคํ”ผ ์˜ˆ์ œ: ์ƒํ™ฉ์— ๋”ฐ๋ผ coffe ๊ฐ์ฒด์— ์ฑ…์ž„์„ ๋ง๋ถ™์ž„

ย 

โ—ย ๊ณ ์ŠคํŠธ ์˜ˆ์ œ: ์ƒํ™ฉ์— ๋”ฐ๋ผ apiMethod ํ•จ์ˆ˜์— ์ฑ…์ž„์„ ๋ง๋ถ™์ž„

ย 

=> ์ƒํ™ฉ์— ๋”ฐ๋ผ ์–ด๋–ค ๊ฐ์ฒด์— ์ฑ…์ž„์„ ๋ง๋ถ™์ด๋Š” ํŒจํ„ด

๋‹ค์‹œ ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด๋ณด๋ฉด...

Observe Pattern

Observe

Observe

function Product() {
  this.price = 0;
  this.actions = [];
}

Product.prototype.setBasePrice = function(val) {
  this.price = val;
  this.notifyAll();
};

Product.prototype.register = function(observer) {
  this.actions.push(observer);
};

Product.prototype.unregister = function(observer) {
  this.actions = this.actions.filter(function(el) {
    return el != observer;
  });
};

Product.prototype.notifyAll = function() {
  return this.actions.forEach(function(el) {
    el.update(this);
  }.bind(this));
};

var fees = {
  update: function(product) {
    product.price = product.price * 1.2;
  }
};

var proft = {
  update: function(product) {
    product.price = product.price * 2;
  }
};

Observe

โ—ย ๊ด€์ฐฐ์ž ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค.

Facade Pattern

Facade

์„œ๋ธŒ์‹œ์Šคํ…œ์˜ ๋‹จ์ˆœํ™”๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŒจํ„ด

Facade

์„œ๋ธŒ์‹œ์Šคํ…œ์˜ ๋‹จ์ˆœํ™”๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŒจํ„ด

// discount, shipping, fees ์‹คํ–‰
var shopFacade = {
  calc: function(price) {
    price = discount(price);
    price = fees(price);
    price += shipping();
    return price;
  }
};

// ํ• ์ธ
function discount(value) {
  return value * 0.9;
}

// ๋ฐฐ์†ก๋ฃŒ
function shipping() {
  return 5;
}

// ์ˆ˜์ˆ˜๋ฃŒ
function fees(value) {
  return value * 1.05;
}

Facade

โ—ย ์ƒˆ๋กœ์šด ํŒจํ„ด์ด ์•„๋‹ˆ๋‹ค. ํ‰์†Œ์— ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค.

ย 

โ— ์ˆœ์„œ์„ฑ์„ ๋ณด์žฅํ•ด์•ผ ๋œ๋‹ค๋ฉด ํผ์‚ฌ๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉ

ย 

โ— DB ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋„ ํผ์‚ฌ๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

Mediator Pattern

Mediator

๊ฐ์ฒด๊ฐ„์˜ M:N๊ด€๊ณ„์—์„œ M:1๋กœ ๊ด€๊ณ„๋ฅผ ๋‚ฎ์ถ”๋Š” ํŒจํ„ด

Mediator

function TrafficTower() {
  this.airplanes = [];
}

TrafficTower.prototype.requestPositions = function() {
  return this.airplanes.map(function(airplane) {
    return airplane.position;
  });
};

function Airplane(position, trafficTower) {
  this.position = position;
  this.trafficTower = trafficTower;
  this.trafficTower.airplanes.push(this);
}

Airplane.prototype.requestPositions = function() {
  return this.trafficTower.requestPositions();
};

Mediator

โ—ย ๋ณต์žกํ•œ ๊ด€๊ณ„๋ฅผ ์ธํ„ฐํŽ˜์ด์Šคํ™” ํ•˜๋Š” ์ ์—์„œ Facade์™€ ์œ ์‚ฌํ•œ ์ ์ด ์žˆ๋‹ค.
ย 

โ— ์—ฐ๊ด€๋˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์ค‘๊ณ„์— ๋”ฐ๋ฅธ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•˜๋ฏ€๋กœ ์ƒํ™ฉ์„ ํ™•์‹คํžˆ
ย  ย  ํŒŒ์•…ํ•ด์•ผ๋  ๊ฒƒ ๊ฐ™๋‹ค.

ย 

๋””์ž์ธ ํŒจํ„ด์€ ์™„๋ฒฝํ•œ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹ˆ๋‹ค

JavaScript: Design Patterns

By Jaewoo KIM

JavaScript: Design Patterns

33-js-concepts

  • 350