๐ก ์ฌ๋ฌ ํจํด์ ํจ๊ป ์ฌ์ฉํ์ฌ ๋์์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ณตํฉ ํจํด์ด๋ผํ๋ค.
์ค๋ฆฌ ์๋ฎฌ๋ ์ด์ ๊ฒ์์ ์ฒ์๋ถํฐ ๋ค์ ๋ง๋ค๋ฉด์ ๊ธฐ๋ฅ์ ์ถ๊ฐํด๋ณด์.
์ค๋ฆฌ๋ ๋ชจ๋ ์ธ์์๋ฆฌ๋ฅผ ๋ผ ์ ์์ผ๋ฏ๋ก 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 ํจํด์ ๋ชจ๋ธ-๋ทฐ-์ปจํธ๋กค๋ฌ๋ฅผ ์ค์ธ ํํ์ด๋ค.
View- ๋ชจ๋ธ์ ํํํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ค.
- ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ฉด ๋ณ๊ฒฝ ํต์ง์ ๋ํ ์ฒ๋ฆฌ๋ฐฉ๋ฒ์ ๊ตฌํํด์ผํ๋ค. ๋ทฐ์ ๋ณ๊ฒฝ์
Controller์๊ฒ ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ ๊ตฌํํด์ผํ๋ค. - ํ์ํ ๋ ํ์ํ ์ํ์ ๋ฐ์ดํฐ๋ ๋ชจ๋ธ์์ ์ง์ ๊ฐ์ ธ์จ๋ค. ์ด๋ ๊ด์ ์ ๋ฐ๋ผ ๋ค๋ฅด๋ค. ๋ชจ๋ธ์ด๋ ์ปจํธ๋กค๋ฌ๋ฅผ ๋ชฐ๋ผ์ผํ๋ค๋ ๊ด์ ๋ ์๋ค. ํ์คํ๊ฑด ๋ชจ๋ธ์ ์ฌ์ฉํ ํ์ ์ ๋ณด๋ฅผ ์ ์ฅํด์๋ ์๋๋ค.
Controller- ์ฌ์ฉ์๋ก๋ถํฐ ์ ๋ ฅ์ ๋ฐ์ผ๋ฉฐ ์ ๋ ฅ๋ฐ์ ๋ด์ฉ์ด ๋ชจ๋ธ์๊ฒ ์ด๋ค ์๋ฏธ๊ฐ ์๋์ง ํ์ ํ๋ค.
Model๊ณผ ๋ทฐ๋ ์๋ก๋ฅผ ๋ชจ๋ฅด๊ณ , ๋ณ๊ฒฝ์ ์ธ๋ถ๋ก ์๋ฆฌ๊ณ , ์์ ํ๋ ๋ฐฉ๋ฒ์ ๊ฐ์ง๊ณ ์์ด ์ด๋ฅผ ์ปจํธ๋กค๋ฌ๊ฐ ์ค์ฌํ๊ธฐ ์ํดModel๊ณผView๋ฅผ ๊ตฌ์ฑํ๊ณ ์์ด์ผํ๋ค.
Model- ๋ชจ๋ธ์ ๋ชจ๋ ๋ฐ์ดํฐ, ์ํ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ ๊ฐ์ง๊ณ ์์ด์ผํ๋ค.
- ๋ทฐ์ ์ปจํธ๋กค๋ฌ์์ ๋ชจ๋ธ์ ์ํ๋ฅผ ์กฐ์ํ๊ฑฐ๋ ๊ฐ์ ธ์ฌ ๋ ํ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํด์ผํ๋ค.
- ๋ชจ๋ธ์ด ์์ ์ ์ํ ๋ณํ๋ฅผ
์ต์ ๋ฒ(View)์๊ฒ ํต์งํ๋ ๋ฐฉ๋ฒ์ ๊ตฌํํด์ผ ํ๋ค. View๋Controller์ ๋ํ ์ด๋ ํ ์ ๋ณด๋ ์์ง ๋ง์์ผํ๋ค.
- ์ฌ์ฉ์๋ ๋ทฐ์๋ง ์ ์ดํ ์ ์๋ค. ๋ทฐ๋ ๋ชจ๋ธ์ ๋ณด์ฌ์ฃผ๋ ์ฐฝ์ด๋ผ๊ณ ํ ์ ์๋ค. ์ฌ์ฉ์๊ฐ ๋ทฐ์ ๋ญ๊ฐ๋ฅผ ํ๋ฉด ๋ทฐ๋ ๋ฌด์จ ์ผ์ด ์ผ์ด๋ฌ๋์ง ์ปจํธ๋กค๋ฌ์๊ฒ ์๋ ค์ฃผ๊ณ ์ปจํธ๋กค๋ฌ๋ ์ํฉ์ ๋ง๊ฒ ์์ ํ๋ค.
- ์ปจํธ๋กค๋ฌ๊ฐ ๋ชจ๋ธ์๊ฒ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ผ๊ณ ์์ฒญํ๋ค. ์ปจํธ๋กค๋ฌ๋ ์ฌ์ฉ์์ ์์ฒญ์ ๋ฐ์์ ํด์ํ๊ณ (์๋ฆฌ๋ฅผ ํค์ฐ๋ ๋ฒํผ, ๋ด๋ฆฌ๋ ๋ฒํผ ๋ฑ๋ฑ), ๋ชจ๋ธ์ ์ด๋ค ์์ผ๋ก ์กฐ์ํด์ผํ๋์ง ๊ฒฐ์ ํ๋ค.
- ์ปจํธ๋กค๋ฌ๊ฐ ๋ทฐ๋ฅผ ๋ณ๊ฒฝํด๋ฌ๋ผ๊ณ ์์ฒญํ ์๋ ์๋ค. ์ปจํธ๋กค๋ฌ๋ ๋ทฐ๋ก๋ถํฐ ์ด๋ค ํ๋์ ๋ฐ์์ ๋, ๊ทธ ํ๋์ ๊ฒฐ๊ณผ๋ก ๋ทฐ์๊ฒ ๋ญ๊ฐ๋ฅผ ๋ฐ๊ฟ ๋ฌ๋ผ๊ณ ํ ์ ์๋ค. ์๋ฅผ ๋ค์ด, ์ธํฐํ์ด์ค์ ์๋ ๋ฒํผ์ด๋ ๋ฉ๋ด๋ฅผ ๋นํ์ฑํํ ์ ์๋ค.
- ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ๋ชจ๋ธ์ด ๋ทฐ์๊ฒ ๊ทธ ์ฌ์ค์ ์๋ฆฐ๋ค. ์ฌ์ฉ์์ ํ๋์ด๋ ๋ค๋ฅธ ๋ด๋ถ์ ์ธ ๋ณํ๋ฑ์ผ๋ก ๋ชจ๋ธ์์ ๋ญ๊ฐ๊ฐ ๋ฐ๋๋ฉด ๋ชจ๋ธ์ ๋ทฐ์๊ฒ ์ํ๊ฐ ๋ณ๊ฒฝ๋์๋ค๊ณ ์๋ฆฐ๋ค.
- ๋ทฐ๊ฐ ๋ชจ๋ธ์๊ฒ ์ํ๋ฅผ ์์ฒญํ๋ค. ๋ทฐ๋ ํ๋ฉด์ ํ์ํ ์ํ๋ฅผ ๋ชจ๋ธ๋ก๋ถํฐ ์ง์ ๊ฐ์ ธ์จ๋ค. ๋ชจ๋ธ์ด ๋ทฐ์๊ฒ ์๋ก์ด ๊ณก์ด ์ฌ์๋์๋ค๊ณ ์๋ ค์ฃผ๋ฉด ๋ทฐ๋ ๋ชจ๋ธ์๊ฒ ๊ณก ์ ๋ชฉ์ ์์ฒญํ๊ณ , ๊ทธ๊ฒ์ ๋ฐ์์ ํ๋ฉด์ ํ์ํ๋ค.
์ ๋ฐฉ๋ฒ์ ํตํด ๋ชจ๋ธ, ๋ทฐ, ์ปจํธ๋กค๋ฌ๊ฐ ์๋ก ๋์จํ๊ฒ ๊ฒฐํฉ๋์ด ๊น๋ํ๋ฉด์๋ ์ ์ฐํ ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค.
์๋ก์ด ๋ชจ๋ธ์ ๊ธฐ์กด์ ๋ทฐ์ ์ปจํธ๋กค๋ฌ์์ ์ฐ๊ฒฐํด์ ์ธ ๋๋ ์ด๋ํฐ ํจํด์ ํ์ฉํ ์ ์๋ค.
์๋ง์ ์น ํ๋ ์์ํฌ์๋ MVC๊ฐ ์ ์ฉ๋์ด์๋ค.
thin ํด๋ผ์ด์ธํธ ์ ๊ทผ๋ฒ: ๋๋ถ๋ถ์ ๋ชจ๋ธ๊ณผ ๋ทฐ, ๊ทธ๋ฆฌ๊ณ ์ปจํธ๋กค๋ฌ๊ฐ ๋ชจ๋ ์๋ฒ๋ก ๋ค์ด๊ฐ๊ณ ๋ธ๋ผ์ฐ์ ๋ ๋ทฐ๋ฅผ ํ๋ฉด์ ํ์ํ๊ณ ์ปจํธ๋กค๋ฌ๋ก ์ ๋ ฅ์ ๋ฐ์์ค๋ ์ญํ ๋ง ํ๋ค.๋จ์ผ ํ์ด์ง ์ ํ๋ฆฌ์ผ์ด์ : ๋๋ถ๋ถ์ ๋ชจ๋ธ๊ณผ ๋ทฐ, ๊ทธ๋ฆฌ๊ณ ์ปจํธ๋กค๋ฌ๊น์ง ํด๋ผ์ด์ธํธ์ ๋ค์ด๊ฐ๋ค.
๋ชจ๋ธ์ ์ต์ ๋ฒ ํจํด์ ์จ์ ์ํ๊ฐ ๋ณ๊ฒฝ๋์์ ๋ ๊ทธ ๋ชจ๋ธ๊ณผ ์ฐ๊ด๋ ๊ฐ์ฒด๋ค์๊ฒ ์ฐ๋ฝํ๋ค.
์ด๋ฅผ ํตํด ๋ชจ๋ธ์ ๋ทฐ์ ์ปจํธ๋กค๋ฌ๋ก๋ถํฐ ์์ ํ ๋ ๋ฆฝ์ํฌ ์ ์๋ค.
๋ทฐ์ ์ปจํธ๋กค๋ฌ๋ ๊ณ ์ ์ ์ธ ์ ๋ต ํจํด์ผ๋ก ๊ตฌํ๋์ด์๋ค.
๋ทฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒ๋ชจ์ต์๋ง ์ ๊ฒฝ์ ์ฐ๊ณ , ์ธํฐํ์ด์ค์ ํ๋์ ๊ฒฐ์ ํ๋ ์ผ์ ๋ชจ๋ ์ปจํธ๋กค๋ฌ์ ์บก์ํํ๋ค.
๋, ์ฌ์ฉ์๊ฐ ์์ฒญํ ๋ด์ญ์ ์ฒ๋ฆฌํ๋ ค๊ณ ๋ชจ๋ธ๊ณผ ์๊ธฐํ๋ ์ผ์ ์ปจํธ๋กค๋ฌ๊ฐ ๋งก๊ฒ๋์ด ๋ชจ๋ธ๊ณผ ๋ทฐ๋ฅผ ๋ถ๋ฆฌํ ์ ์๋ค.
๋์คํ๋ ์ด๋ ์ฌ๋ฌ ๋จ๊ณ๋ก ๊ฒน์ณ์๋ ์๋์ฐ, ํจ๋, ๋ฒํผ ๋ฑ์ผ๋ก ๊ตฌ์ฑ๋์ด์๋ค.
์ปจํธ๋กค๋ฌ๊ฐ ๋ทฐ์๊ฒ ํ๋ฉด์ ๊ฐฑ์ ํด ๋ฌ๋ผ๊ณ ์์ฒญํ๋ฉด ์ต์์ ๋ทฐ ๊ตฌ์ฑ ์์์๊ฒ๋ง ํ๋ฉด์ ๊ฐฑ์ ํ๋ผ๊ณ ์๊ธฐํ๋ฉด ๋๋ค.
View๋ ์ฌ์ฉ์๊ฐ BPM ์ ์ด ๋๊ตฌ๋ฅผ ์ค์ ํ๋ ํ๋ฉด์ ํํํ๋ ์ฑ ์์ ๊ฐ๋๋ค.Model์ ๋นํธ๋ฅผ ์กฐ์ ํ๊ณ ๋ ธ๋๋ฅผ ๋ด๋ณด๋ด๋ ๋ฑ์ ์์ ์ ํ๋ค.Controller๋View์Model์ฌ์ด์์ ์ฌ์ฉ์์ ์ ๋ ฅ์ ๋ฐํ์ผ๋กModel์ด ํด์ผํ๋ ์ ์ ํ ํ๋์ผ๋ก ๋ฐ๊พผ๋ค.
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์๊ฒ ์ฐ๋ฝ์ ์ทจํ๊ธฐ ์ํด ์ต์ ๋ฒ ํจํด์ ์ฌ์ฉํ๋ค.
ํ์ฌ 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๋ ๊ทธ์ ์๋ง๋ ์ฒ๋ฆฌ๋ฅผ ํ๋ค.
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);
}
}


