전략을 쉽게 바꿀 수 있도록 해주는 디자인 패턴
var Strategy = (function() {
function Strategy() {
this.strategy = null;
}
Strategy.prototype.setStrategy = function(strategy) {
this.strategy = strategy;
};
Strategy.prototype.execute = function() {
this.strategy.execute();
};
return Strategy;
})();
var ShipStrategy = (function() {
function ShipStrategy() {}
ShipStrategy.prototype.execute = function() {
console.log('배로 이탈리아에 갑니다');
};
return ShipStrategy;
})();
var LandStrategy = (function() {
function LandStrategy() {}
LandStrategy.prototype.execute = function() {
console.log('육로로 이탈리아에 갑니다');
};
return LandStrategy;
})();
var strat = new Strategy();
var ship = new ShipStrategy();
var land = new LandStrategy();
strat.setStrategy(ship);
strat.setStrategy(land); // 전략을 바꿈
strat.execute(); // 어떤 전략이든 설정된 것을 실행
// 육로로 이탈리아에 갑니다.
const Strategy = class{
constructor(){
this.strategy = null;
}
setStrategy(strategy){
this.strategy = strategy;
}
execute() {
this.strategy.execute();
};
}
const ShipStrategy = class{
constructor(){};
execute(){
console.log('배로 이탈리아에 갑니다');
}
}
const LandStrategy = class{
constructor() {}
execute() {
console.log('육로로 이탈리아에 갑니다');
}
};
var strat = new Strategy();
var ship = new ShipStrategy();
var land = new LandStrategy();
strat.setStrategy(ship);
strat.setStrategy(land); // 전략을 바꿈
strat.execute(); // 어떤 전략이든 설정된 것을 실행
// 육로로 이탈리아에 갑니다.
전략을 설정하는 부분 따로, 실행하는 부분 따로라서, 전략을 설정해두면 실행하기 전에 자유롭게 전략을 바꿀 수 있다.
효과
Unit Test가 용이해진다.
코드의 재활용성을 높여준다.
객체 간의 의존성(종속성)을 줄이거나 없엘 수 있다.
객체 간의 결합도이 낮추면서 유연한 코드를 작성할 수 있다.
기존의 Binder
const Binder = class {
#items = new Set;
add(v, _ = type(v, BinderItem)) {
this.#items.add(v);
}
render(viewmodel, _ = type(viewmodel, ViewModel)) {
this.#items.forEach(item => {
const vm = type(viewmodel[item.viewmodel], ViewModel), el = item.el;
Object.entries(vm.styles).forEach(([k, v]) => el.style[k] = v);
Object.entries(vm.attributes).forEach(([k, v]) => el.setAttribute(k, v));
Object.entries(vm.properties).forEach(([k, v]) => el[k] = v);
Object.entries(vm.events).forEach(([k, v]) => el['on' + k] = e => v.call(el, e, viewmodel)); // this 를 el 로 바인딩
});
}
};
수정 binder
const Binder = class {
#item = new Set
#processors = {} // category당 한 개의 processor를 사용하게 하기 위함
// 자료구조를 선택할 때 심각하게 생각해야 한다.
add (v, _ = type(v, BinderItem)) { this.#item.add(v) }
// Strategy를 주입 받는다.
addProcessor (v, _ = type(v, Processor)) { this.#processors[v.category] = v }
// Render에서 주입 받은 Strategy를 사용한다.
render (viewmodel, _ = type(viewmodel, ViewModel)) {
const processores = Object.entries(this.#processors)
this.#item.forEach(item => {
const vm = type(viewmodel[item.viewmodel], ViewModel), el = item.el
processores.forEach(([pk, processor]) => {
Object.entries(vm[pk]).forEach(([k, v]) => {
processor.process(vm, el, k, v)
})
})
})
}
}
binder.addProcessor(new class extends Processor {
_process (vm, el, k, v) { el.style[k] = v }
}('styles'))
binder.addProcessor(new class extends Processor {
_process (vm, el, k, v) { el.setAttribute(k, v) }
}('attributes'))
binder.addProcessor(new class extends Processor {
_process (vm, el, k, v) { el[k] = v }
}('properties'))
binder.addProcessor(new class extends Processor {
_process (vm, el, k, v) { el[`on${k}`] = e => v.call(el, e, vm) }
}('events'))
binder가 프로세서를 주입받는다.
객체에 직접 새로운 속성을 정의하거나 이미 존재하는 속성을 수정한 후, 그 객체를 반환합니다.
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// throws an error in strict mode
console.log(object1.property1);
// expected output: 42
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: true
});
object1.property1 = 77;
console.log(object1.property1);
// expected output: 77