Skip to content

Latest commit

ย 

History

History
1017 lines (765 loc) ยท 28.2 KB

File metadata and controls

1017 lines (765 loc) ยท 28.2 KB

๋ณตํ•ฉ ํŒจํ„ด

๐Ÿ’ก ์—ฌ๋Ÿฌ ํŒจํ„ด์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ๋””์ž์ธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณตํ•ฉ ํŒจํ„ด์ด๋ผํ•œ๋‹ค.


์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„์— ๋‹ค์–‘ํ•œ ํŒจํ„ด ์ ์šฉํ•ด๋ณด๊ธฐ

์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋งŒ๋“ค๋ฉด์„œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด๋ณด์ž.


์˜ค๋ฆฌ๋Š” ๋ชจ๋‘ ์šธ์Œ์†Œ๋ฆฌ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Quackable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

public interface Quackable {
    public void quack();
}

Quackable์„ ๊ตฌํ˜„ํ•ด์„œ ์˜ค๋ฆฌ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.

public class MallardDuck implements Quackable{
    @Override
    public void quack() {
        System.out.println("๊ฝฅ๊ฝฅ");
    }
}

// ๋“ฑ๋“ฑ์˜ ์—ฌ๋Ÿฌ ์˜ค๋ฆฌ๋“ค

์ด์ œ ๋‹คํ˜•์„ฑ์„ ํ™œ์šฉํ•ด ๋ชจ๋“  Quackable ๊ตฌํ˜„์ฒด์—์„œ quack ๋ฉ”์†Œ๋“œ๋“ค์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		simulator.simulate();
	}

	void simulate() {
		Quackable mallardDuck = new MallardDuck();
		Quackable redheadDuck = new RedheadDuck();
		
		System.out.println("\n์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„");
 
		simulate(mallardDuck);
		simulate(redheadDuck);
	}
 
	// ๋‹คํ˜•์„ฑ์ด ํ™œ์šฉ๋จ.
	void simulate(Quackable duck) {
		duck.quack();
	}
}

์–ด๋Œ‘ํ„ฐ ํŒจํ„ด

์ด๋•Œ ๋‹ค๋ฅด๊ฒŒ ์šฐ๋Š” Goose ๊ฐ์ฒด๊ฐ€ ์ƒ๊ฒผ๋‹ค๊ณ  ํ•˜์ž. Goose ๊ฐ์ฒด๋Š” ๊ฑฐ์œ„๋ผ์„œ quack() ๋ฉ”์†Œ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ honk() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์šธ ์ˆ˜ ์žˆ๋‹ค.

์ด๋•Œ, Goose ๋Š” Quackable์„ ์ƒ์†ํ•˜์—ฌ quack ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์–ด๋Œ‘ํ„ฐ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ์•ผํ•œ๋‹ค.


Goose

public class Goose {
	public void honk() {
		System.out.println("๋ฝ๋ฝ");
	}
}

GooseAdapter

public class GooseAdapter implements Quackable {
	Goose goose;
 
	public GooseAdapter(Goose goose) {
		this.goose = goose;
	}
 
	public void quack() {
		goose.honk();
	}

}

์›๋ž˜ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑ์œผ๋กœ ํ•˜์—ฌ Quackable์„ ๊ตฌํ˜„ํ•˜๋Š” GooseAdapter ๊ตฌํ˜„ํ•˜์˜€๋‹ค.


Simulator

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		simulator.simulate();
	}

	void simulate() {
		Quackable mallardDuck = new MallardDuck();
		Quackable redheadDuck = new RedheadDuck();
		Quackable goose = new GooseAdapter(new Goose());
		System.out.println("\n์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„");
 
		simulate(mallardDuck);
		simulate(redheadDuck);
		simulate(goose);
	}

	// ๋‹คํ˜•์„ฑ์ด ํ™œ์šฉ๋จ.
	void simulate(Quackable duck) {
		duck.quack();
	}
}

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด

Quackable์— ๋ช‡๋ฒˆ์˜ ์†Œ๋ฆฌ๋ฅผ ๋‚ด๋Š”์ง€ ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋ฅผ ์œ„ํ•ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด๋ณด์ž.


decorator

public class QuackCounter implements Quackable{
    Quackable duck;
    static int numberOfQuacks;

    public QuackCounter(Quackable duck) {
        this.duck = duck;
    }

    @Override
    public void quack() {
        duck.quack();
        numberOfQuacks++;
    }

    public static int getNumberOfQuacks() {
        return numberOfQuacks;
    }
}

Duck ๊ฐ์ฒด๋ฅผ ๊ฐ์‹ธ ๊ฐ์ฒด์— ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.


Simulator

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		simulator.simulate();
	}

	void simulate() {
		Quackable mallardDuck = new QuackCounter(new MallardDuck());
		Quackable redheadDuck = new QuackCounter(new RedheadDuck());
		Quackable goose = new GooseAdapter(new Goose());
		System.out.println("\n์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„");
 
		simulate(mallardDuck);
		simulate(redheadDuck);
		simulate(goose);

		System.out.println(QuackCounter.getNumberOfQuacks());
	}

	// ๋‹คํ˜•์„ฑ์ด ํ™œ์šฉ๋จ.
	void simulate(Quackable duck) {
		duck.quack();
	}
}

ํŒฉํ† ๋ฆฌ ํŒจํ„ด

์œ„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ฐ์ฒด๋ฅผ ๋ฌด์กฐ๊ฑด ํฌ์žฅ์„ ํ•ด์ฃผ์–ด์•ผ๋งŒ ํ•œ๋‹ค.

์ฆ‰, ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ผ๋„ ์ž˜ ๊ด€๋ฆฌ ๋˜์–ด์•ผํ•œ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ์ ์šฉํ•ด๋ณด์ž.


Factory

public abstract class AbstractDuckFactory {
    public abstract Quackable createMallardDuck();
    public abstract Quackable createRedheadDuck();
}

public class CountingDuckFactory extends AbstractDuckFactory{
    @Override
    public Quackable createMallardDuck() {
        return new QuackCounter(new MallardDuck());
    }

    @Override
    public Quackable createRedheadDuck() {
        return new QuackCounter(new RedheadDuck());
    }
}

์ถ”์ƒ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค์–ด ๊ฐœ์ˆ˜๋ฅผ ์…€ ์ˆ˜ ์žˆ๋Š” DuckFactory ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ Duck์„ ๋ฐ˜ํ™˜ํ•˜๋Š” Factory๋„ ๊ตฌํ˜„ํ•˜์—ฌ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.


Simulator

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		AbstractDuckFactory duckFactory = new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}

	void simulate(AbstractDuckFactory duckFactory) {
		Quackable mallardDuck = duckFactory.createMallardDuck();
		Quackable redheadDuck = duckFactory.createRedheadDuck();
		Quackable goose = new GooseAdapter(new Goose());
		System.out.println("\n์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„");
 
		simulate(mallardDuck);
		simulate(redheadDuck);
		simulate(goose);

		System.out.println(QuackCounter.getNumberOfQuacks());
	}

	// ๋‹คํ˜•์„ฑ์ด ํ™œ์šฉ๋จ.
	void simulate(Quackable duck) {
		duck.quack();
	}
}

ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด์˜ ์ƒ์„ฑ๋„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.


์ปดํฌ์ง€ํŠธ ํŒจํ„ด๊ณผ ๋ฐ˜๋ณต์ž ํŒจํ„ด

์œ„์˜ ์—ฌ๋Ÿฌ ์˜ค๋ฆฌ ๋ฌด๋ฆฌ๋“ค์„ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ํ•˜๋‚˜ํ•˜๋‚˜ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋‹ค.

๊ฐ์ฒด๋“ค๋กœ ๊ตฌ์„ฑ๋œ ์ปฌ๋ ‰์…˜์„ ๊ฐœ๋ณ„ ๊ฐ์ฒด์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์ปดํฌ์ง€ํŠธ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด ์˜ค๋ฆฌ๋“ค์„ ๋ชจ๋‘ ๊ด€๋ฆฌํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

๋˜, ์ด ์ปฌ๋ ‰์…˜์— ๋ฐ˜๋ณต์ž ํŒจํ„ด์„ ์ ์š”ํ•ด๋ณด์ž.


Composite

public class Flock implements Quackable{
    List<Quackable> quackers = new ArrayList<>();

    public void add(Quackable quacker) {
        quackers.add(quacker);
    }

    @Override
    public void quack() {
        // ๋ฐ˜๋ณต์ž ํŒจํ„ด
        Iterator<Quackable> iterator = quackers.iterator();
        while (iterator.hasNext()) {
            Quackable quacker = iterator.next();
            quacker.quack();
        }
    }
}

Simulator

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		AbstractDuckFactory duckFactory = new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}

	void simulate(AbstractDuckFactory duckFactory) {
		Quackable mallardDuck = duckFactory.createMallardDuck();
		Quackable redheadDuck = duckFactory.createRedheadDuck();
		Quackable goose = new GooseAdapter(new Goose());
		System.out.println("\n์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„");

		Flock flockOfDucks = new Flock();

		flockOfDucks.add(mallardDuck);
		flockOfDucks.add(redheadDuck);
		flockOfDucks.add(goose);

		simulate(flockOfDucks);

		System.out.println(QuackCounter.getNumberOfQuacks());
	}

	// ๋‹คํ˜•์„ฑ์ด ํ™œ์šฉ๋จ.
	void simulate(Quackable duck) {
		duck.quack();
	}
}

์•ˆ์ •์„ฑ vs ํˆฌ๋ช…์„ฑ

์ปดํฌ์ง€ํŠธ ํŒจํ„ด์„ ์ƒ๊ฐํ•  ๋•Œ, ๋ณตํ•ฉ ๊ฐ์ฒด(๋ถ€๋ชจ ๋…ธ๋“œ)์™€ ์žŽ ๊ฐ์ฒด(์ž์‹ ๋…ธ๋“œ)์— ๋˜‘๊ฐ™์€ ๋ฉ”์†Œ๋“œ๊ฐ€ ๋“ค์–ด์žˆ์—ˆ๋‹ค. ์ฆ‰, ์žŽ ๊ฐ์ฒด์—๋Š” ํ•„์š” ์—†๋Š” ๋ณตํ•ฉ ๊ฐ์ฒด ๋ฉ”์†Œ๋“œ๋“ค์ด ํฌํ•จ๋˜์–ด์•ผํ–ˆ๊ณ , ๋ณตํ•ฉ ๊ฐ์ฒด์—๋Š” ํ•„์š” ์—†๋Š” ์žŽ ๊ฐ์ฒด ๋ฉ”์†Œ๋“œ๋“ค์ด ํฌํ•จ๋˜์–ด์•ผ ํ–ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ณตํ•ฉ ๊ฐ์ฒด์™€ ์žŽ ๊ฐ์ฒด ์‚ฌ์ด์˜ ์ฐจ์ด์ ์„ ํˆฌ๋ช…ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด ํด๋ผ์ด์–ธํŠธ๋Š” ์–ด๋–ค ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๊ณ  ์žˆ๋Š”์ง€ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ  ๋ฌด์กฐ๊ฑด ๊ฐ™์€ ๋ฉ”์†Œ๋“ค๋ฅด ํ˜ธ์ถœํ•˜๋ฉด ๋๋‹ค.

์œ„ ์ฝ”๋“œ์—์„œ๋Š” ๋ณตํ•ฉ ๊ฐ์ฒด์—์„œ ์ž์‹์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋ณตํ•ฉ ๊ฐ์ฒด์—๋งŒ ๋„ฃ์—ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์žŽ ๊ฐ์ฒด๋“ค์€ add() ๋ฉ”์†Œ๋“œ ์ž์ฒด๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์•ˆ์ „์„ฑ์„ ํ™•๋ณดํ•˜๊ธด ํ•˜์ง€๋งŒ, ๋ณตํ•ฉ ๊ฐ์ฒด์™€ ์žŽ ๊ฐ์ฒด ์‚ฌ์ด์˜ ์ฐจ์ด๊ฐ€ ๋‘๋“œ๋Ÿฌ์ ธ ํˆฌ๋ช…์„ฑ์„ ์žƒ๊ฒŒ ๋œ๋‹ค. ์ฆ‰, ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ์–ด๋–ค ๊ฐ์ฒด๋ฅผ ๋ณตํ•ฉ ๊ฐ์ฒด์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ทธ ๊ฐ์ฒด๊ฐ€ Flock์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ํ™•์‹คํžˆ ํ•ด์•ผํ•œ๋‹ค.


์˜ต์ €๋ฒ„ ํŒจํ„ด

์˜ค๋ฆฌ๊ฐ€ ์šธ ๋•Œ ์•Œ๋ฆผ์„ ๋ฐ›๋Š” ์˜ค๋ฆฌํ•™์ž ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด๋ณด์ž.

์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ๋งŒ๋“ค ๋•Œ, Observable ๋ณด์กฐ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‹ค์ œ QuackObservable(์‹ค์ œ ์˜ค๋ฆฌ ๊ฐ์ฒด๋“ค)์— ๊ตฌ์„ฑ์œผ๋กœ ํฌํ•จํ•˜์—ฌ ๋“ฑ๋ก ์˜ต์ €๋ฒ„์— ๋“ฑ๋ก ๋ฐ ์—ฐ๋ฝํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์บก์Аํ™”ํ•ด๋ณด์ž.

์ฆ‰, ์‹ค์ œ ๋“ฑ๋ก ๋ฐ ์—ฐ๋ฝ ์ฝ”๋“œ๋Š” Observable์— ํฌํ•จ๋˜๊ณ , QuackObservable์ด ํ•„์š”ํ•œ ์ž‘์—…์„ Observable ๋ณด์กฐ ํด๋ž˜์Šค์— ์ „๋ถ€ ์œ„์ž„ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.


QuackObservable

public interface QuackObservable {
    void registerObserver(Observer observer);
    void notifyObservers();
}

// ๋ชจ๋“  ์šธ ์ˆ˜ ์žˆ๋Š” ์˜ค๋ฆฌ ๊ฐ์ฒด๋“ค์ด ๊ด€์ฐฐ ๋Œ€์ƒ
public interface Quackable extends QuackObservable{
    public void quack();
}

// ๊ตฌํ˜„์ฒด
public class MallardDuck implements Quackable{

    Observable observable;

    public MallardDuck() {
        this.observable = new Observable(this);
    }

    @Override
    public void quack() {
        System.out.println("๊ฝฅ๊ฝฅ");
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer observer) {
        observable.registerObserver(observer);
    }

    @Override
    public void notifyObservers() {
        observable.notifyObservers();
    }
}

์‹ค์ œ ์˜ต์ €๋ฒ„์— ๋“ฑ๋ก ๋ฐ ์—ฐ๋ฝํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•  Observable ํด๋ž˜์Šค๋ฅผ ๊ตฌ์„ฑ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

Quackable์ด QuackObservable์„ ์ƒ์†ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์œผ๋ฏ€๋กœ, Quackable์„ ์ƒ์†๋ฐ›๋Š” ๋ชจ๋“  ๊ฐ์ฒด์—์„œ๋„ QuackObservable ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ๋งŒํ•œ๋‹ค.


Observable

public class Observable implements QuackObservable{
    List<Observer> observers = new ArrayList<>();
    QuackObservable duck;

    public Observable(QuackObservable duck) {
        this.duck = duck;
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(duck);
        }
    }
}

Observable์€ ์—ฌ๋Ÿฌ ์˜ต์ €๋ฒ„๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Observer ์ปฌ๋ ‰์…˜์œผ๋กœ ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ๊ณ , ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ๋Š” ์˜ต์ €๋ฒ„๋“ค์— ์—ฐ๋ฝ์„ ๋Œ๋ฆฌ๋Š” ์ฝ”๋“œ๋ฅผ ์‹ค์งˆ์ ์œผ๋กœ ๋งก๊ณ  ์žˆ๋‹ค.


Observer

public interface Observer {
    void update(QuackObservable duck);
}

public class Quackologist implements Observer{
    @Override
    public void update(QuackObservable duck) {
        System.out.println("๊ฝฅ๊ฝฅ ํ•™์ž: "+ duck + "์ด ๋ฐฉ๊ธˆ ์†Œ๋ฆฌ๋ฅผ ์ณค๋‹ค.");
    }
}

Composite

public class Flock implements Quackable{
    List<Quackable> quackers = new ArrayList<>();

    public void add(Quackable quacker) {
        quackers.add(quacker);
    }

    @Override
    public void quack() {
        // ๋ฐ˜๋ณต์ž ํŒจํ„ด
        Iterator<Quackable> iterator = quackers.iterator();
        while (iterator.hasNext()) {
            Quackable quacker = iterator.next();
            quacker.quack();
        }
    }

    @Override
    public void registerObserver(Observer observer) {
        for (Quackable duck : quackers) {
            duck.registerObserver(observer);
        }
    }

    @Override
    public void notifyObservers() {

    }
}

Composite ๊ฐ์ฒด์—์„œ ์˜ค๋ฆฌ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ Composite ๊ฐ์ฒด์— ์žˆ๋Š” ์˜ค๋ฆฌ๋“ค์„ ํ•œ๋ฒˆ์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๊ฒŒ๋” ๋ฉ”์†Œ๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.


Simulator

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		AbstractDuckFactory duckFactory = new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}

	void simulate(AbstractDuckFactory duckFactory) {
		Quackable mallardDuck = duckFactory.createMallardDuck();
		Quackable redheadDuck = duckFactory.createRedheadDuck();
		Quackable goose = new GooseAdapter(new Goose());
		System.out.println("\n์˜ค๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒŒ์ž„");

		Flock flockOfDucks = new Flock();

		flockOfDucks.add(mallardDuck);
		flockOfDucks.add(redheadDuck);
		flockOfDucks.add(goose);

		Quackologist quackologist = new Quackologist();
		flockOfDucks.registerObserver(quackologist);

		simulate(flockOfDucks);

		System.out.println(QuackCounter.getNumberOfQuacks());
	}

	// ๋‹คํ˜•์„ฑ์ด ํ™œ์šฉ๋จ.
	void simulate(Quackable duck) {
		duck.quack();
	}
}

Composite ๊ฐ์ฒด์—์„œ ํ•œ๋ฒˆ์— ์˜ต์ €๋ฒ„๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.


์œ„์—์„œ ๋งŽ์€ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์˜€๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ํŒจํ„ด์„ ์„ž์–ด์„œ ์‚ฌ์šฉํ–ˆ๋‹ค๊ณ  ๋ณตํ•ฉ ํŒจํ„ด์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์—†๋‹ค. ๋ณตํ•ฉ ํŒจํ„ด์€ ๋ช‡๊ฐœ์˜ ํŒจํ„ด์„ ๋ณตํ•ฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์„œ ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์–ด์•ผํ•œ๋‹ค.


MVC ํŒจํ„ด

MVC ํŒจํ„ด์€ ๋ชจ๋ธ-๋ทฐ-์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ค„์ธ ํ‘œํ˜„์ด๋‹ค.

MVC

  • View
    • ๋ชจ๋ธ์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.
    • ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚˜๋ฉด ๋ณ€๊ฒฝ ํ†ต์ง€์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค. ๋ทฐ์˜ ๋ณ€๊ฒฝ์„ Controller ์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.
    • ํ‘œ์‹œํ•  ๋•Œ ํ•„์š”ํ•œ ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋Š” ๋ชจ๋ธ์—์„œ ์ง์ ‘ ๊ฐ€์ ธ์˜จ๋‹ค. ์ด๋Š” ๊ด€์ ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค. ๋ชจ๋ธ์ด๋‚˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋ชฐ๋ผ์•ผํ•œ๋‹ค๋Š” ๊ด€์ ๋„ ์žˆ๋‹ค. ํ™•์‹คํ•œ๊ฑด ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•œ ํ›„์— ์ •๋ณด๋ฅผ ์ €์žฅํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.
  • Controller
    • ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ์„ ๋ฐ›์œผ๋ฉฐ ์ž…๋ ฅ๋ฐ›์€ ๋‚ด์šฉ์ด ๋ชจ๋ธ์—๊ฒŒ ์–ด๋–ค ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•œ๋‹ค.
    • Model ๊ณผ ๋ทฐ๋Š” ์„œ๋กœ๋ฅผ ๋ชจ๋ฅด๊ณ , ๋ณ€๊ฒฝ์„ ์™ธ๋ถ€๋กœ ์•Œ๋ฆฌ๊ณ , ์ˆ˜์‹ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์ด๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ค‘์žฌํ•˜๊ธฐ ์œ„ํ•ด Model ๊ณผ View๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ์–ด์•ผํ•œ๋‹ค.
  • Model
    • ๋ชจ๋ธ์€ ๋ชจ๋“  ๋ฐ์ดํ„ฐ, ์ƒํƒœ์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผํ•œ๋‹ค.
    • ๋ทฐ์™€ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ชจ๋ธ์˜ ์ƒํƒœ๋ฅผ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ ๊ฐ€์ ธ์˜ฌ ๋•Œ ํ•„์š”ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ด์•ผํ•œ๋‹ค.
    • ๋ชจ๋ธ์ด ์ž์‹ ์˜ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์˜ต์ €๋ฒ„(View) ์—๊ฒŒ ํ†ต์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.
    • View๋‚˜ Controller์— ๋Œ€ํ•œ ์–ด๋– ํ•œ ์ •๋ณด๋„ ์•Œ์ง€ ๋ง์•„์•ผํ•œ๋‹ค.

  1. ์‚ฌ์šฉ์ž๋Š” ๋ทฐ์—๋งŒ ์ ‘์ด‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ทฐ๋Š” ๋ชจ๋ธ์„ ๋ณด์—ฌ์ฃผ๋Š” ์ฐฝ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋ทฐ์— ๋ญ”๊ฐ€๋ฅผ ํ•˜๋ฉด ๋ทฐ๋Š” ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚ฌ๋Š”์ง€ ์ปจํŠธ๋กค๋Ÿฌ์—๊ฒŒ ์•Œ๋ ค์ฃผ๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ž‘์—…ํ•œ๋‹ค.
  2. ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ชจ๋ธ์—๊ฒŒ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ผ๊ณ  ์š”์ฒญํ•œ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ๋ฐ›์•„์„œ ํ•ด์„ํ•˜๊ณ (์†Œ๋ฆฌ๋ฅผ ํ‚ค์šฐ๋Š” ๋ฒ„ํŠผ, ๋‚ด๋ฆฌ๋Š” ๋ฒ„ํŠผ ๋“ฑ๋“ฑ), ๋ชจ๋ธ์„ ์–ด๋–ค ์‹์œผ๋กœ ์กฐ์ž‘ํ•ด์•ผํ•˜๋Š”์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.
  3. ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ทฐ๋ฅผ ๋ณ€๊ฒฝํ•ด๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋ทฐ๋กœ๋ถ€ํ„ฐ ์–ด๋–ค ํ–‰๋™์„ ๋ฐ›์•˜์„ ๋•Œ, ๊ทธ ํ–‰๋™์˜ ๊ฒฐ๊ณผ๋กœ ๋ทฐ์—๊ฒŒ ๋ญ”๊ฐ€๋ฅผ ๋ฐ”๊ฟ” ๋‹ฌ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ธํ„ฐํŽ˜์ด์Šค์— ์žˆ๋Š” ๋ฒ„ํŠผ์ด๋‚˜ ๋ฉ”๋‰ด๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
  4. ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ชจ๋ธ์ด ๋ทฐ์—๊ฒŒ ๊ทธ ์‚ฌ์‹ค์„ ์•Œ๋ฆฐ๋‹ค. ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์ด๋‚˜ ๋‹ค๋ฅธ ๋‚ด๋ถ€์ ์ธ ๋ณ€ํ™”๋“ฑ์œผ๋กœ ๋ชจ๋ธ์—์„œ ๋ญ”๊ฐ€๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ชจ๋ธ์€ ๋ทฐ์—๊ฒŒ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๊ณ  ์•Œ๋ฆฐ๋‹ค.
  5. ๋ทฐ๊ฐ€ ๋ชจ๋ธ์—๊ฒŒ ์ƒํƒœ๋ฅผ ์š”์ฒญํ•œ๋‹ค. ๋ทฐ๋Š” ํ™”๋ฉด์— ํ‘œ์‹œํ•  ์ƒํƒœ๋ฅผ ๋ชจ๋ธ๋กœ๋ถ€ํ„ฐ ์ง์ ‘ ๊ฐ€์ ธ์˜จ๋‹ค. ๋ชจ๋ธ์ด ๋ทฐ์—๊ฒŒ ์ƒˆ๋กœ์šด ๊ณก์ด ์žฌ์ƒ๋˜์—ˆ๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๋ฉด ๋ทฐ๋Š” ๋ชจ๋ธ์—๊ฒŒ ๊ณก ์ œ๋ชฉ์„ ์š”์ฒญํ•˜๊ณ , ๊ทธ๊ฒƒ์„ ๋ฐ›์•„์„œ ํ™”๋ฉด์— ํ‘œ์‹œํ•œ๋‹ค.

์œ„ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ๋ชจ๋ธ, ๋ทฐ, ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์„œ๋กœ ๋А์Šจํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ๊น”๋”ํ•˜๋ฉด์„œ๋„ ์œ ์—ฐํ•œ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ƒˆ๋กœ์šด ๋ชจ๋ธ์„ ๊ธฐ์กด์˜ ๋ทฐ์™€ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์—ฐ๊ฒฐํ•ด์„œ ์“ธ ๋•Œ๋Š” ์–ด๋Œ‘ํ„ฐ ํŒจํ„ด์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์›น๊ณผ MVC

์ˆ˜๋งŽ์€ ์›น ํ”„๋ ˆ์ž„์›Œํฌ์—๋„ MVC๊ฐ€ ์ ์šฉ๋˜์–ด์žˆ๋‹ค.

  • thin ํด๋ผ์ด์–ธํŠธ ์ ‘๊ทผ๋ฒ• : ๋Œ€๋ถ€๋ถ„์˜ ๋ชจ๋ธ๊ณผ ๋ทฐ, ๊ทธ๋ฆฌ๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ชจ๋‘ ์„œ๋ฒ„๋กœ ๋“ค์–ด๊ฐ€๊ณ  ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ทฐ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ž…๋ ฅ์„ ๋ฐ›์•„์˜ค๋Š” ์—ญํ• ๋งŒ ํ•œ๋‹ค.
  • ๋‹จ์ผ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ : ๋Œ€๋ถ€๋ถ„์˜ ๋ชจ๋ธ๊ณผ ๋ทฐ, ๊ทธ๋ฆฌ๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๊นŒ์ง€ ํด๋ผ์ด์–ธํŠธ์— ๋“ค์–ด๊ฐ„๋‹ค.

์˜ต์ €๋ฒ„ ํŒจํ„ด

Observer

๋ชจ๋ธ์€ ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ์จ์„œ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ๊ทธ ๋ชจ๋ธ๊ณผ ์—ฐ๊ด€๋œ ๊ฐ์ฒด๋“ค์—๊ฒŒ ์—ฐ๋ฝํ•œ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ๋ชจ๋ธ์„ ๋ทฐ์™€ ์ปจํŠธ๋กค๋Ÿฌ๋กœ๋ถ€ํ„ฐ ์™„์ „ํžˆ ๋…๋ฆฝ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.


์ „๋žต ํŒจํ„ด

Strategy

๋ทฐ์™€ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ณ ์ „์ ์ธ ์ „๋žต ํŒจํ„ด์œผ๋กœ ๊ตฌํ˜„๋˜์–ด์žˆ๋‹ค.

๋ทฐ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒ‰๋ชจ์Šต์—๋งŒ ์‹ ๊ฒฝ์„ ์“ฐ๊ณ , ์ธํ„ฐํŽ˜์ด์Šค์˜ ํ–‰๋™์„ ๊ฒฐ์ •ํ•˜๋Š” ์ผ์€ ๋ชจ๋‘ ์ปจํŠธ๋กค๋Ÿฌ์— ์บก์Аํ™”ํ•œ๋‹ค.

๋˜, ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ ๋‚ด์—ญ์„ ์ฒ˜๋ฆฌํ•˜๋ ค๊ณ  ๋ชจ๋ธ๊ณผ ์–˜๊ธฐํ•˜๋Š” ์ผ์„ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋งก๊ฒŒ๋˜์–ด ๋ชจ๋ธ๊ณผ ๋ทฐ๋ฅผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.


์ปดํฌ์ง€ํŠธ ํŒจํ„ด

Composite

๋””์Šคํ”Œ๋ ˆ์ด๋Š” ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ๊ฒน์ณ์žˆ๋Š” ์œˆ๋„์šฐ, ํŒจ๋„, ๋ฒ„ํŠผ ๋“ฑ์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด์žˆ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ทฐ์—๊ฒŒ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•ด ๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•˜๋ฉด ์ตœ์ƒ์œ„ ๋ทฐ ๊ตฌ์„ฑ ์š”์†Œ์—๊ฒŒ๋งŒ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•˜๋ผ๊ณ  ์–˜๊ธฐํ•˜๋ฉด ๋œ๋‹ค.


MVC๋กœ BPM ์ œ์–ด๋„๊ตฌ ๋งŒ๋“ค๊ธฐ

  • View๋Š” ์‚ฌ์šฉ์ž๊ฐ€ BPM ์ œ์–ด ๋„๊ตฌ๋ฅผ ์„ค์ •ํ•˜๋Š” ํ™”๋ฉด์„ ํ‘œํ˜„ํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ–๋Š”๋‹ค.
  • Model์€ ๋น„ํŠธ๋ฅผ ์กฐ์ ˆํ•˜๊ณ  ๋…ธ๋ž˜๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ํ•œ๋‹ค.
  • Controller๋Š” View์™€ Model ์‚ฌ์ด์—์„œ ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ๋ฐ”ํƒ•์œผ๋กœ Model์ด ํ•ด์•ผํ•˜๋Š” ์ ์ ˆํ•œ ํ–‰๋™์œผ๋กœ ๋ฐ”๊พผ๋‹ค.

Model BeatModel

Model์˜ ๋‚ด๋ถ€ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ ๋ทฐ์—๊ฒŒ ๋ฐ”๋€Œ์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ณต์œ ํ•ด์•ผํ•˜๋ฏ€๋กœ, ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.


Observer BeatObserver, BPMObserver

public interface BeatObserver {
	void updateBeat();
}

public interface BPMObserver {
	void updateBPM();
}

Model BeatModel

public interface BeatModelInterface {
	void initialize();
  
	void on();
  
	void off();
  
    void setBPM(int bpm);
  
	int getBPM();

	// ๋ชจ๋ธ์€ ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ๋‹ค.
	void registerObserver(BeatObserver o);
  
	void removeObserver(BeatObserver o);
  
	void registerObserver(BPMObserver o);
  
	void removeObserver(BPMObserver o);
}

public class BeatModel implements BeatModelInterface, Runnable {
	List<BeatObserver> beatObservers = new ArrayList<BeatObserver>();
	List<BPMObserver> bpmObservers = new ArrayList<BPMObserver>();
	int bpm = 90;
	// ์Šค๋ ˆ๋“œ์™€ flag๋ฅผ ํ†ตํ•ด์„œ ๋…ธ๋ž˜ ์žฌ์ƒ
	Thread thread;
	boolean stop = false;
	Clip clip;

	public void initialize() {
		try {
			File resource = new File("clap.wav");
			clip = (Clip) AudioSystem.getLine(new Line.Info(Clip.class));
			clip.open(AudioSystem.getAudioInputStream(resource));
		}
		catch(Exception ex) {
			System.out.println("Error: Can't load clip");
			System.out.println(ex);
		}
	}

	public void on() {
		bpm = 90;
		//notifyBPMObservers();
		thread = new Thread(this);
		stop = false;
		thread.start();
	}

	public void off() {
		stopBeat();
		stop = true;
	}

	public void run() {
		while (!stop) {
			playBeat();
			notifyBeatObservers();
			try {
				Thread.sleep(60000/getBPM());
			} catch (Exception e) {}
		}
	}

	public void setBPM(int bpm) {
		this.bpm = bpm;
		notifyBPMObservers();
	}

	public int getBPM() {
		return bpm;
	}

	public void registerObserver(BeatObserver o) {
		beatObservers.add(o);
	}

	public void notifyBeatObservers() {
		for(int i = 0; i < beatObservers.size(); i++) {
			BeatObserver observer = (BeatObserver)beatObservers.get(i);
			observer.updateBeat();
		}
	}

	public void registerObserver(BPMObserver o) {
		bpmObservers.add(o);
	}

	public void notifyBPMObservers() {
		for(int i = 0; i < bpmObservers.size(); i++) {
			BPMObserver observer = (BPMObserver)bpmObservers.get(i);
			observer.updateBPM();
		}
	}

	public void removeObserver(BeatObserver o) {
		int i = beatObservers.indexOf(o);
		if (i >= 0) {
			beatObservers.remove(i);
		}
	}

	public void removeObserver(BPMObserver o) {
		int i = bpmObservers.indexOf(o);
		if (i >= 0) {
			bpmObservers.remove(i);
		}
	}

	public void playBeat() {
		clip.setFramePosition(0);
		clip.start();
	}
	public void stopBeat() {
		clip.setFramePosition(0);
		clip.stop();
	}

}

์ฆ‰, Model์€ ๊ฐ์ข… ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๊ณ  ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ View์—๊ฒŒ ์—ฐ๋ฝ์„ ์ทจํ•˜๊ธฐ ์œ„ํ•ด ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ๋‹ค.


View DJView

ํ˜„์žฌ BPM๊ณผ ํ†ตํ†ต ํŠ€๋Š” ๋ง‰๋Œ€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํ™”๋ฉด๊ณผ ์ œ์–ด์šฉ ์ธํ„ฐํŽ˜์ด์Šค ๋‘๊ฐœ์˜ ํ™”๋ฉด์„ ๋งŒ๋“ ๋‹ค.


View DJView

public class DJView implements ActionListener, BeatObserver, BPMObserver {
	BeatModelInterface model;
	ControllerInterface controller;
    JFrame viewFrame;
    JPanel viewPanel;
	BeatBar beatBar;
	JLabel bpmOutputLabel;
    JFrame controlFrame;
    JPanel controlPanel;
    JLabel bpmLabel;
    JTextField bpmTextField;
    JButton setBPMButton;
    JButton increaseBPMButton;
    JButton decreaseBPMButton;
    JMenuBar menuBar;
    JMenu menu;
    JMenuItem startMenuItem;
    JMenuItem stopMenuItem;

    public DJView(ControllerInterface controller, BeatModelInterface model) {	
		this.controller = controller;
		this.model = model;
		model.registerObserver((BeatObserver)this);
		model.registerObserver((BPMObserver)this);
    }
    
    public void createView() {
		// Create all Swing components here
        viewPanel = new JPanel(new GridLayout(1, 2));
        viewFrame = new JFrame("View");
        viewFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        viewFrame.setSize(new Dimension(100, 80));
        bpmOutputLabel = new JLabel("offline", SwingConstants.CENTER);
		beatBar = new BeatBar();
		beatBar.setValue(0);
        JPanel bpmPanel = new JPanel(new GridLayout(2, 1));
		bpmPanel.add(beatBar);
        bpmPanel.add(bpmOutputLabel);
        viewPanel.add(bpmPanel);
        viewFrame.getContentPane().add(viewPanel, BorderLayout.CENTER);
        viewFrame.pack();
        viewFrame.setVisible(true);
	}
  

    // ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์— ๋”ฐ๋ผ ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ
    public void createControls() {
		// Create all Swing components here
        JFrame.setDefaultLookAndFeelDecorated(true);
        controlFrame = new JFrame("Control");
        controlFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        controlFrame.setSize(new Dimension(100, 80));

        controlPanel = new JPanel(new GridLayout(1, 2));

        menuBar = new JMenuBar();
        menu = new JMenu("DJ Control");
        startMenuItem = new JMenuItem("Start");
        menu.add(startMenuItem);
        startMenuItem.addActionListener((event) -> controller.start());
        // was....
        /*
        startMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                controller.start();
            }
        });
        */
        stopMenuItem = new JMenuItem("Stop");
        menu.add(stopMenuItem); 
        stopMenuItem.addActionListener((event) -> controller.stop());
        // was...
        /*
        stopMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                controller.stop();
            }
        });
        */
        JMenuItem exit = new JMenuItem("Quit");
        exit.addActionListener((event) -> System.exit(0));
        // was...
        /*
        exit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                System.exit(0);
            }
        });
        */

        menu.add(exit);
        menuBar.add(menu);
        controlFrame.setJMenuBar(menuBar);

        bpmTextField = new JTextField(2);
        bpmLabel = new JLabel("Enter BPM:", SwingConstants.RIGHT);
        setBPMButton = new JButton("Set");
        setBPMButton.setSize(new Dimension(10,40));
        increaseBPMButton = new JButton(">>");
        decreaseBPMButton = new JButton("<<");
        setBPMButton.addActionListener(this);
        increaseBPMButton.addActionListener(this);
        decreaseBPMButton.addActionListener(this);

        JPanel buttonPanel = new JPanel(new GridLayout(1, 2));

		buttonPanel.add(decreaseBPMButton);
		buttonPanel.add(increaseBPMButton);

        JPanel enterPanel = new JPanel(new GridLayout(1, 2));
        enterPanel.add(bpmLabel);
        enterPanel.add(bpmTextField);
        JPanel insideControlPanel = new JPanel(new GridLayout(3, 1));
        insideControlPanel.add(enterPanel);
        insideControlPanel.add(setBPMButton);
        insideControlPanel.add(buttonPanel);
        controlPanel.add(insideControlPanel);
        
        bpmLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        bpmOutputLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

        controlFrame.getRootPane().setDefaultButton(setBPMButton);
        controlFrame.getContentPane().add(controlPanel, BorderLayout.CENTER);

        controlFrame.pack();
        controlFrame.setVisible(true);
    }

	public void enableStopMenuItem() {
    	stopMenuItem.setEnabled(true);
	}

	public void disableStopMenuItem() {
    	stopMenuItem.setEnabled(false);
	}

	public void enableStartMenuItem() {
    	startMenuItem.setEnabled(true);
	}

	public void disableStartMenuItem() {
    	startMenuItem.setEnabled(false);
	}

    public void actionPerformed(ActionEvent event) {
		if (event.getSource() == setBPMButton) {
			int bpm = 90;
			String bpmText = bpmTextField.getText();
			if (bpmText == null || bpmText.contentEquals("")) {
				bpm = 90;
			} else {
				bpm = Integer.parseInt(bpmTextField.getText());
			}
        	controller.setBPM(bpm);
		} else if (event.getSource() == increaseBPMButton) {
			controller.increaseBPM();
		} else if (event.getSource() == decreaseBPMButton) {
			controller.decreaseBPM();
		}
    }

    // ์˜ต์ €๋ฒ„ ํŒจํ„ด
    // ๋ชจ๋ธ์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋Š” ์—ฐ๋ฝ์„ ๋ฐ›์œผ๋ฉด View์˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ๋ถˆ๋ ค์„œ ํ™”๋ฉด ๋ณ€๊ฒฝ
	public void updateBPM() {
		if (model != null) {
			int bpm = model.getBPM();
			if (bpm == 0) {
				if (bpmOutputLabel != null) {
        			bpmOutputLabel.setText("offline");
				}
			} else {
				if (bpmOutputLabel != null) {
        			bpmOutputLabel.setText("Current BPM: " + model.getBPM());
				}
			}
		}
	}
  
	public void updateBeat() {
		if (beatBar != null) {
			 beatBar.setValue(100);
		}
	}
}

์˜ต์ €๋ฒ„ ํŒจํ„ด์— ๋”ฐ๋ผ ๋ชจ๋ธ์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋Š” ์•Œ๋ฆผ์„ ๋ฐ›๋Š”๋‹ค. ์ด๋•Œ, push ๋ฐฉ์‹์ด ์•„๋‹Œ pull ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๋˜ ์ž…๋ ฅ์— ๋”ฐ๋ผ controller๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , controller๋Š” ๊ทธ์— ์•Œ๋งž๋Š” ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.


Controller BeatController

public interface ControllerInterface {
    void start();
    void stop();
    void increaseBPM();
    void decreaseBPM();
    void setBPM(int bpm);
}

public class BeatController implements ControllerInterface {
	BeatModelInterface model;
	DJView view;
  
	// ๋ทฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ธ์ž๋กœ model์„ ๋ฐ›์•„์˜จ๋‹ค.
	public BeatController(BeatModelInterface model) {
		this.model = model;
		view = new DJView(this, model);
        view.createView();
        view.createControls();
		view.disableStopMenuItem();
		view.enableStartMenuItem();
		model.initialize();
	}
  
	// ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค€๋‹ค.
	public void start() {
		model.on();
		view.disableStartMenuItem();
		view.enableStopMenuItem();
	}
  
	public void stop() {
		model.off();
		view.disableStopMenuItem();
		view.enableStartMenuItem();
	}
    
	public void increaseBPM() {
        int bpm = model.getBPM();
        model.setBPM(bpm + 1);
	}
    
	public void decreaseBPM() {
        int bpm = model.getBPM();
        model.setBPM(bpm - 1);
  	}
  
 	public void setBPM(int bpm) {
		model.setBPM(bpm);
	}
}