Open kkirico opened 3 months ago
interface Quackable {
quack(): void;
}
class MallardDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class RedheadDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class DuckCall implements Quackable {
quack() {
console.log('꽥꽥');
}
}
class RubberDuck implements Quackable {
quack() {
console.log('삑삑');
}
}
class Goose {
honk() {
console.log('끽끽');
}
}
class GooseAdapter implements Quackable {
constructor(private goose: Goose) {}
quack() {
this.goose.honk();
}
}
function simulate(duck: Quackable) {
duck.quack();
}
simulate(new MallardDuck());
simulate(new RedheadDuck());
simulate(new DuckCall());
simulate(new RubberDuck());
simulate(new GooseAdapter(new Goose()));
만약 오리 클래스는 그대로 두면서 오리가 꽥꽥 소리낸 횟수를 세려면 어떤 패턴을 써야될까?
interface Quackable {
quack(): void;
}
class MallardDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class RedheadDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class DuckCall implements Quackable {
quack() {
console.log('꽥꽥');
}
}
class RubberDuck implements Quackable {
quack() {
console.log('삑삑');
}
}
class Goose {
honk() {
console.log('끽끽');
}
}
class GooseAdapter implements Quackable {
constructor(private goose: Goose) {}
quack() {
this.goose.honk();
}
}
function simulate(duck: Quackable) {
duck.quack();
}
class QuackCounter implements Quackable {
duck: Quackable;
static numberOfQuacks = 0;
constructor(duck: Quackable) {
this.duck = duck;
}
quack() {
this.duck.quack();
QuackCounter.numberOfQuacks++;
}
}
// simulate(new MallardDuck());
// simulate(new RedheadDuck());
// simulate(new DuckCall());
// simulate(new RubberDuck());
// simulate(new GooseAdapter(new Goose()));
const mallardDuck = new MallardDuck();
const redheadDuck = new RedheadDuck();
const duckCall = new DuckCall();
const rubberDuck = new RubberDuck();
const gooseAdapter = new GooseAdapter(new Goose());
const mallardDuckCounter = new QuackCounter(mallardDuck);
const redheadDuckCounter = new QuackCounter(redheadDuck);
const duckCallCounter = new QuackCounter(duckCall);
const rubberDuckCounter = new QuackCounter(rubberDuck);
const gooseAdapterCounter = new QuackCounter(gooseAdapter);
simulate(mallardDuckCounter);
simulate(redheadDuckCounter);
simulate(duckCallCounter);
simulate(rubberDuckCounter);
simulate(gooseAdapterCounter);
console.log(QuackCounter.numberOfQuacks);
어쩌다 counter를 붙이는걸 까먹는 경우가 있다. 오리 생성을 캡슐화 해서 빠지지 않도록 해준다.
interface Quackable {
quack(): void;
}
class MallardDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class RedheadDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class DuckCall implements Quackable {
quack() {
console.log('꽥꽥');
}
}
class RubberDuck implements Quackable {
quack() {
console.log('삑삑');
}
}
class Goose {
honk() {
console.log('끽끽');
}
}
class GooseAdapter implements Quackable {
constructor(private goose: Goose) {}
quack() {
this.goose.honk();
}
}
function simulate(duck: Quackable) {
duck.quack();
}
class QuackCounter implements Quackable {
duck: Quackable;
static numberOfQuacks = 0;
constructor(duck: Quackable) {
this.duck = duck;
}
quack() {
this.duck.quack();
QuackCounter.numberOfQuacks++;
}
}
abstract class AbstractDuckFactory {
abstract createMallardDuck(): Quackable;
abstract createRedheadDuck(): Quackable;
abstract createDuckCall(): Quackable;
abstract createRubberDuck(): Quackable;
}
class CountingDuckFactory extends AbstractDuckFactory {
createDuckCall(): Quackable {
return new QuackCounter(new DuckCall());
}
createMallardDuck(): Quackable {
return new QuackCounter(new MallardDuck());
}
createRedheadDuck(): Quackable {
return new QuackCounter(new RedheadDuck());
}
createRubberDuck(): Quackable {
return new QuackCounter(new RubberDuck());
}
}
const duckFactory = new CountingDuckFactory();
const mallardDuck = duckFactory.createMallardDuck();
const redheadDuck = duckFactory.createRedheadDuck();
const duckCall = duckFactory.createDuckCall();
const rubberDuck = duckFactory.createRubberDuck();
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(new GooseAdapter(new Goose()));
console.log(QuackCounter.numberOfQuacks);
오리들을 한 번에 관리하고 싶다.
interface Quackable {
quack(): void;
}
class MallardDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class RedheadDuck implements Quackable {
quack() {
console.log('꽉꽉');
}
}
class DuckCall implements Quackable {
quack() {
console.log('꽥꽥');
}
}
class RubberDuck implements Quackable {
quack() {
console.log('삑삑');
}
}
class Goose {
honk() {
console.log('끽끽');
}
}
class GooseAdapter implements Quackable {
constructor(private goose: Goose) {}
quack() {
this.goose.honk();
}
}
function simulate(duck: Quackable) {
duck.quack();
}
class QuackCounter implements Quackable {
duck: Quackable;
static numberOfQuacks = 0;
constructor(duck: Quackable) {
this.duck = duck;
}
quack() {
this.duck.quack();
QuackCounter.numberOfQuacks++;
}
}
abstract class AbstractDuckFactory {
abstract createMallardDuck(): Quackable;
abstract createRedheadDuck(): Quackable;
abstract createDuckCall(): Quackable;
abstract createRubberDuck(): Quackable;
}
class CountingDuckFactory extends AbstractDuckFactory {
createDuckCall(): Quackable {
return new QuackCounter(new DuckCall());
}
createMallardDuck(): Quackable {
return new QuackCounter(new MallardDuck());
}
createRedheadDuck(): Quackable {
return new QuackCounter(new RedheadDuck());
}
createRubberDuck(): Quackable {
return new QuackCounter(new RubberDuck());
}
createGooseAdapter(): Quackable {
return new GooseAdapter(new Goose());
}
}
class Flock implements Quackable {
ducks: Quackable[] = [];
add(duck: Quackable) {
this.ducks.push(duck);
}
quack() {
this.ducks.forEach(duck => duck.quack());
}
}
const duckFactory = new CountingDuckFactory();
const mallardDuck = duckFactory.createMallardDuck();
const redheadDuck = duckFactory.createRedheadDuck();
const duckCall = duckFactory.createDuckCall();
const rubberDuck = duckFactory.createRubberDuck();
const flockOfDucks = new Flock();
flockOfDucks.add(mallardDuck);
flockOfDucks.add(redheadDuck);
flockOfDucks.add(duckCall);
flockOfDucks.add(rubberDuck);
simulate(flockOfDucks);
console.log(QuackCounter.numberOfQuacks);
오리를 관찰하고 싶음.
interface Observer {
update(duck: QuackObservable): void;
}
interface QuackObservable {
registerObserver(observer: Observer): void;
notifyObservers(): void;
}
interface Quackable extends QuackObservable {
quack(): void;
}
class Observable implements QuackObservable {
observers: Observer[] = [];
quackObservable: QuackObservable;
constructor(quackObservable: QuackObservable) {
this.quackObservable = quackObservable;
}
registerObserver(observer: Observer) {
this.observers.push(observer);
}
notifyObservers() {
this.observers.forEach(observer => observer.update(this.quackObservable));
}
}
class MallardDuck implements Quackable {
observable: Observable;
constructor() {
this.observable = new Observable(this);
}
quack() {
console.log('꽉꽉');
this.notifyObservers();
}
registerObserver(observer: Observer) {
this.observable.registerObserver(observer);
}
notifyObservers() {
this.observable.notifyObservers();
}
}
class RedheadDuck implements Quackable {
observable: Observable;
constructor() {
this.observable = new Observable(this);
}
quack() {
console.log('꽉꽉');
this.notifyObservers();
}
registerObserver(observer: Observer) {
this.observable.registerObserver(observer);
}
notifyObservers() {
this.observable.notifyObservers();
}
}
class DuckCall implements Quackable {
observable: Observable;
constructor() {
this.observable = new Observable(this);
}
quack() {
console.log('꽥꽥');
this.notifyObservers();
}
registerObserver(observer: Observer) {
this.observable.registerObserver(observer);
}
notifyObservers() {
this.observable.notifyObservers();
}
}
class RubberDuck implements Quackable {
observalbe: Observable;
constructor() {
this.observalbe = new Observable(this);
}
quack() {
console.log('삑삑');
}
registerObserver(observer: Observer) {
this.observalbe.registerObserver(observer);
}
notifyObservers() {
this.observalbe.notifyObservers();
}
}
class Goose {
honk() {
console.log('끽끽');
}
}
class GooseAdapter implements Quackable {
observalbe: Observable;
constructor(private goose: Goose) {
this.observalbe = new Observable(this);
}
quack() {
this.goose.honk();
this.notifyObservers();
}
registerObserver(observer: Observer) {
this.observalbe.registerObserver(observer);
}
notifyObservers() {
this.observalbe.notifyObservers();
}
}
function simulate(duck: Quackable) {
duck.quack();
}
class QuackCounter implements Quackable {
duck: Quackable;
static numberOfQuacks = 0;
constructor(duck: Quackable) {
this.duck = duck;
}
quack() {
this.duck.quack();
QuackCounter.numberOfQuacks++;
}
registerObserver(observer: Observer) {
this.duck.registerObserver(observer);
}
notifyObservers() {
this.duck.notifyObservers();
}
}
abstract class AbstractDuckFactory {
abstract createMallardDuck(): Quackable;
abstract createRedheadDuck(): Quackable;
abstract createDuckCall(): Quackable;
abstract createRubberDuck(): Quackable;
}
class CountingDuckFactory extends AbstractDuckFactory {
createDuckCall(): Quackable {
return new QuackCounter(new DuckCall());
}
createMallardDuck(): Quackable {
return new QuackCounter(new MallardDuck());
}
createRedheadDuck(): Quackable {
return new QuackCounter(new RedheadDuck());
}
createRubberDuck(): Quackable {
return new QuackCounter(new RubberDuck());
}
createGooseAdapter(): Quackable {
return new GooseAdapter(new Goose());
}
}
class Flock implements Quackable {
ducks: Quackable[] = [];
add(duck: Quackable) {
this.ducks.push(duck);
}
quack() {
this.ducks.forEach(duck => duck.quack());
}
registerObserver(observer: Observer) {
this.ducks.forEach(duck => duck.registerObserver(observer));
}
notifyObservers() {
this.ducks.forEach(duck => duck.notifyObservers());
}
}
class Quackologist implements Observer {
update(duck: QuackObservable) {
console.log('Quackologist: ', duck);
}
}
const duckFactory = new CountingDuckFactory();
const mallardDuck = duckFactory.createMallardDuck();
const redheadDuck = duckFactory.createRedheadDuck();
const duckCall = duckFactory.createDuckCall();
const rubberDuck = duckFactory.createRubberDuck();
const flockOfDucks = new Flock();
flockOfDucks.add(mallardDuck);
flockOfDucks.add(redheadDuck);
flockOfDucks.add(duckCall);
flockOfDucks.add(rubberDuck);
const quackologist = new Quackologist();
flockOfDucks.registerObserver(quackologist);
simulate(flockOfDucks);
console.log(QuackCounter.numberOfQuacks);
2개이상의 패턴을 결합해서 여러가지 문제의 일반적인 해결법을 제시해야한다.
오리 시뮬레이션 게임
Quackable 인터페이스
를 구현하는 구상 오리 클래스
거위를 Quackable 인터페이스에 맞추는 GooseAdapter를 활용한다.
오리가 우는 횟수를 세는 데코레이터 추가
데코레이터로 감싼 오리를 생산하는 팩토리 만들기(팩토리 패턴)
오리 여러 마리를 함께 관리하기
컴포지트 패턴을 활용해서 무리를 다룬다.
*안정성과 투명상 모두 잘 고려해야합니다.
오리 한 마리를 실시간으로 추적
옵저버 패턴을 활용
위와 같이 여러 패턴을 함께 사용할 수 있다.
복합 패턴의 왕
mvc 패턴
모델 - 뷰 - 컨트롤러
모델: 데이터, 상태, 애플리케이션 로직. 뷰와 컨트롤러에 관심없음
뷰: 모델을 표현하는 방법을 제공, 필요한 정보를 모델에서 직접 가져온다.
컨트롤러: 사용자로부터 입력을 받는다.
모델은 옵저버 패턴을 사용해서 상태가 바뀔 때 마다 뷰와 컨트롤러에 연락한다.
뷰와 컨트롤러는 전략패턴을 사용한다.
컨트롤러는 뷰의 행동에 해당한다.
뷰 내부적으로 컴포지트 패턴을 써서 윈도우, 버튼과 같은 다양한 구성요소를 관리한다.