flagtags / OOP-study

0 stars 0 forks source link

복합 패턴 #31

Closed j03y14 closed 4 months ago

j03y14 commented 4 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);