전체 페이지뷰

2017년 5월 12일 금요일

Compound pattern & MVC pattern, part 1

이 전에 사실 Proxy Pattern에 대한 글을 쓰고 있었습니다. 책에서는 자바의 API인 Remote를 사용하였는데 이에 대응하는 것으로 여겨지는 C#의 Remoting은 레거시가 되어 역사의 뒤안길로 밀려나고, 대신 WCF라는 것이 쓰여지기 시작했는데 제 배움과 이해가 짧은 탓에 며칠간을 혼자 끙끙댔지만 도저히 접목시킬 수가 없었습니다. 대신 살펴볼만한 링크를 연결합니다. 혹시 필요하신 분들에게 도움이 되었으면 합니다.

C# 프록시 패턴
WCF 기초(구마상 님의 블로그)

좌절을 겪었지만 꿋꿋이 다음 진도를 나가봅니다. 이번에 알아볼 패턴은 컴파운드 패턴으로 여러 패턴을 섞어 사용하는 것을 말합니다. 그리고 나아가 진정한 의미의 컴파운드 패턴인 모델-뷰-컨트롤러(MVC) 패턴에 대해서 알아보려고 합니다.

이것을 위해 이전에 만들어 보았던 SimUDuck 시뮬레이터를 다시 만나야 합니다.

오리와의 재회


오리 시뮬레이터를 처음부터 만들면서 여러 패턴을 추가하여 기능을 늘리게 될 것입니다. 처음부터 만들어 봅시다.

  • 먼저 Quackable 인터페이스를 만듭니다. 모든 Duck 객체에서 이 인터페이스를 구현하도록 할 것입니다.
public interface Quackable
{
    void Quack();
}
cs


  • Quackable을 구현한 오리 클래스를 만듭니다.
public class MallardDuck : Quackable
{
    public void Quack()
    {
        Console.WriteLine("Quack");
    }
}
public class RedheadDuck : Quackable
{
    public void Quack()
    {
        Console.WriteLine("Quack");
    }
}
cs

조금 다른 Duck 객체도 추가해 봅니다.
public class DuckCall : Quackable
{
    public void Quack()
    {
        Console.WriteLine("Kwak");
    }
}
cs
오리 소리를 내는 호출기 DuckCall입니다.

public class RubberDuck : Quackable
{
    public void Quack()
    {
        Console.WriteLine("Squeak");
    }
}
cs
고무 오리도 추가해 봅니다.


  • 이제 시뮬레이터를 만듭니다.

솔루션 탐색기 상에서 가장 하단 Program.cs를 "DuckSimulator"로 바꾸어주었습니다.

(저는 각각의 클래스와 시뮬레이터 등을 개별 파일로 만드는게 아니라 전부 하나의 프로젝트에 넣어서 작성하고 있기 때문에 이런 방법을 사용하였습니다.)

class DuckSimulator
{
    static void Main(string[] args)
    {
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulate();
    }
    void simulate()
    {
        Quackable mallardDuck = new MallardDuck();
        Quackable readheadDuck = new RedheadDuck();
        Quackable duckCall = new DuckCall();
        Quackable rubberDuck = new RubberDuck();
        Console.WriteLine("\nDuck Simulator");
        simulate(mallardDuck);
        simulate(readheadDuck);
        simulate(duckCall);
        simulate(rubberDuck);
    }
    void simulate(Quackable duck)
    {
        duck.Quack();
    }
}
cs

메인 메소드에서 시뮬레이터를 생성한 후 simulate() 메소드를 호출합니다. 이 메소드는 다형성을 이용하여 파라미터가 없는 것과 있는 것의 두 가지 종류가 마련되어 있습니다. 이제 실행해 보겠습니다.

결과)

Duck Simulator
Quack
Quack
Kwak
Squeak
계속하려면 아무 키나 누르십시오 . . .

아직 별다른 내용이 없으므로 무난히 작동합니다.


  • 오리 있는 곳에 거위도 있다

물이 있는데 오리만 있을 리는 없습니다. 거위도 추가합니다.
public class Goose
{
    public void Honk()
    {
        Console.WriteLine("Honk");
    }
}
cs



  • 거위용 어댑터가 필요합니다.

거위는 Quackable 인터페이스를 구현하고 있지 않으므로 어댑터를 사용하여 시뮬레이터에 들어갈 수 있도록 해 줍니다.

public class GooseAdapter : Quackable
{
    Goose goose;
    public GooseAdapter(Goose goose)
    {
        this.goose = goose;
    }
    public void Quack()
    {
        goose.Honk();
    }
}
cs



  • 거위를 시뮬레이터에 포함시킵니다.

void simulate()
{
    Quackable mallardDuck = new MallardDuck();
    Quackable readheadDuck = new RedheadDuck();
    Quackable duckCall = new DuckCall();
    Quackable rubberDuck = new RubberDuck();
    Quackable gooseDuck = new GooseAdapter(new Goose());
    Console.WriteLine("\nDuck Simulator");
    simulate(mallardDuck);
    simulate(readheadDuck);
    simulate(duckCall);
    simulate(rubberDuck);
    simulate(gooseDuck);
}
cs

Goose를 GooseAdapter로 감싸 Quackbable을 구현하도록 하였습니다. 실행하여 보면...

결과)
Duck Simulator
Quack
Quack
Kwak
Squeak
Honk
계속하려면 아무 키나 누르십시오 . . .

거위가 내는 "Honk" 소리가 포함되었음을 알 수 있습니다.


"꽥 소리"


  • 오리가 내는 꽥 소리의 회수를 세야할 일이 생겼습니다. 꽥학자라는 꽥 소리를 연구하는 집단의 변태같은 요구입니다. 오리 클래스는 그대로 두면서 이 기능을 추가하려면 데코레이터 패턴을 사용합니다.

public class QuackCounter : Quackable
{
    Quackable duck;
    static int numberOfQuacks;
    public QuackCounter(Quackable duck)
    {
        this.duck = duck;
    }
    public void Quack()
    {
        duck.Quack();
        numberOfQuacks++;
    }
    public static int GetQuacks()
    {
        return numberOfQuacks;
    }
}
cs

QuackCounter가 데코레이터입니다. 모든 객체에서 꽥소리를 세야 하므로 정적 변수 하나와 그를 반환해주는 정적 메소드 하나를 추가합니다.

  • 시뮬레이터를 고쳐서 모든 오리를 데코레이터로 감싸줍니다.
class DuckSimulator
{
    static void Main(string[] args)
    {
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulate();
    }
    void simulate()
    {
        Quackable mallardDuck = new QuackCounter(new MallardDuck());
        Quackable readheadDuck = new QuackCounter(new RedheadDuck());
        Quackable duckCall = new QuackCounter(new DuckCall());
        Quackable rubberDuck = new QuackCounter(new RubberDuck());
        Quackable gooseDuck = new GooseAdapter(new Goose());
        Console.WriteLine("\nDuck Simulator");
        simulate(mallardDuck);
        simulate(readheadDuck);
        simulate(duckCall);
        simulate(rubberDuck);
        simulate(gooseDuck);
        Console.WriteLine("오리가 " + QuackCounter.GetQuacks() + "번 꽥꽥거렸습니다.");
    }
    void simulate(Quackable duck)
    {
        duck.Quack();
    }
}
cs

결과)
Duck Simulator
Quack
Quack
Kwak
Squeak
Honk
오리가 4번 꽥꽥거렸습니다.
계속하려면 아무 키나 누르십시오 . . .

그런데 늘 객체를 데코레이터로 감싸주지 않으면 꽥 소리를 제대로 세지 않는 경우가 생깁니다. 이럴 때 오리를 생성하고 데코레이터로 감싸는 부분을 한 군데로 몰아서 해 주면 편리할 듯 합니다.


  • 오리 생산을 위한 팩토리가 필요합니다.

여러 종류의 오리를 생산해야 하므로 추상 팩토리 패턴을 사용하는 것이 좋겠습니다.

public abstract class AbstractDuckFactory
{
    public abstract Quackable CreateMallardDuck();
    public abstract Quackable CreateRedheadDuck();
    public abstract Quackable CreateDuckCall();
    public abstract Quackable CreateRubberDuck();
}
public class CountingDuckFactory : AbstractDuckFactory
{
    public override Quackable CreateMallardDuck()
    {
        return new QuackCounter(new MallardDuck());
    }
    public override Quackable CreateRedheadDuck()
    {
        return new QuackCounter(new RedheadDuck());
    }
    public override Quackable CreateDuckCall()
    {
        return new QuackCounter(new DuckCall());
    }
    public override Quackable CreateRubberDuck()
    {
        return new QuackCounter(new RubberDuck());
    }
}
cs

추상 클래스와 데코레이터로 감싸진 여러 종류의 Duck 객체를 생성해주는 팩토리를 만듭니다.

이제 이것을 사용하도록 시뮬레이터를 고쳐줍니다.

class DuckSimulator
{
    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 readheadDuck = duckFactory.CreateRedheadDuck();
        Quackable duckCall = duckFactory.CreateDuckCall();
        Quackable rubberDuck = duckFactory.CreateRubberDuck();
        Quackable gooseDuck = new GooseAdapter(new Goose());
        Console.WriteLine("\nDuck Simulator");
        simulate(mallardDuck);
        simulate(readheadDuck);
        simulate(duckCall);
        simulate(rubberDuck);
        simulate(gooseDuck);
        Console.WriteLine("오리가 " + QuackCounter.GetQuacks() + "번 꽥꽥거렸습니다.");
    }
    void simulate(Quackable duck)
    {
        duck.Quack();
    }
}
cs

실행 결과는 전과 같습니다.

그런데 이 많은 오리 종류를 하나하나 관리해주는 것이 힘들어지기 시작합니다. 오리들의 컬렉션을 다룰 수 있는 방법이 필요합니다.


  • 오리떼(Quackable 떼)를 만들어 봅시다.

컴포짓과 이터레이터가 필요할 것 같습니다.

public class Flock : Quackable
{
    List<Quackable> quackers = new List<Quackable>();
    public void Add(Quackable quacker)
    {
        quackers.Add(quacker);
    }
    public void Quack()
    {
        IEnumerator iterator = quackers.GetEnumerator();
        while (iterator.MoveNext())
        {
            Quackable quacker = (Quackable)iterator.Current;
            quacker.Quack();
        }
    }
}
cs

다시 시뮬레이터를 수정합니다.
class DuckSimulator
{
    static void Main(string[] args)
    {
        // 동일
    }
    void simulate(AbstractDuckFactory duckFactory)
    {            
        Quackable readheadDuck = duckFactory.CreateRedheadDuck();
        Quackable duckCall = duckFactory.CreateDuckCall();
        Quackable rubberDuck = duckFactory.CreateRubberDuck();
        Quackable gooseDuck = new GooseAdapter(new Goose());
        Console.WriteLine("\nDuck Simulator : With Composite - Flocks");
        Flock flockOfDucks = new Flock();
        flockOfDucks.Add(readheadDuck);
        flockOfDucks.Add(duckCall);
        flockOfDucks.Add(rubberDuck);
        flockOfDucks.Add(gooseDuck);
        Flock flockOfMallards = new Flock();
        Quackable mallardOne = duckFactory.CreateMallardDuck();
        Quackable mallardTwo = duckFactory.CreateMallardDuck();
        Quackable mallardThree = duckFactory.CreateMallardDuck();
        Quackable mallardFour = duckFactory.CreateMallardDuck();
        flockOfMallards.Add(mallardOne);
        flockOfMallards.Add(mallardTwo);
        flockOfMallards.Add(mallardThree);
        flockOfMallards.Add(mallardFour);
        flockOfDucks.Add(flockOfMallards);
        Console.WriteLine("\nDuck Simulator: Whole Flock Simulation");
        simulate(flockOfDucks);
        Console.WriteLine("\nDuck Simulator: Mallard Flock Simulation");
        simulate(flockOfMallards);
        Console.WriteLine("오리가 " + QuackCounter.GetQuacks() + "번 꽥꽥거렸습니다.");
    }
    void simulate(Quackable duck)
    {
        duck.Quack();
    }
}
cs

결과)
Duck Simulator : With Composite - Flocks

Duck Simulator: Whole Flock Simulation
Quack
Kwak
Squeak
Honk
Quack
Quack
Quack
Quack

Duck Simulator: Mallard Flock Simulation
Quack
Quack
Quack
Quack
오리가 11번 꽥꽥거렸습니다.
계속하려면 아무 키나 누르십시오 . . .


컴포짓으로 오리떼를 관리할 수 있게 되었습니다. 이번엔 반대로 오리 하나씩도 챙길 수 있도록 하려고 합니다. 꽥꽥거리는 오리들을 하나씩 실시간으로 추적할 수 있도록 하려는 것이죠.


  • 옵저버 패턴이 필요합니다.

Observable 인터페이스를 먼저 구현하고 옵저버를 등록하는 메소드와 옵저버에게 연락을 돌리는 메소드를 필요로 합니다. 옵저버를 제거하는 메소드는 여기서는 편의상 생략합니다.

public interface Observer
{
    void Update(QuackObservable duck);
}
public interface QuackObservable
{
    void RegisterObserver(Observer observer);
    void NotifyOberver();
}
cs

그리고 모든 Quackable이 이 인터페이스를 구현하도록 만듭니다.
public interface Quackable : QuackObservable
{
    void Quack();
}
cs

이렇게까지 하고 나면 각 구상 클래스에서도 인터페이스의 메소드들을 다 구현하도록 작성해야 합니다. 실제 일일이 구현할 수도 있지만 이번에는 등록과 연락을 위한 코드를 Observable이라는 한 클래스에 캡슐화 시켜두고 구성을 통해 QuackObservale에 포함시키려 합니다.

public class Observable : QuackObservable
{
    List<Observer> observers = new List<Observer>();
    QuackObservable duck;
    public Observable(QuackObservable duck)
    {
        this.duck = duck;
    }
    public void RegisterObserver(Observer observer)
    {
        observers.Add(observer);
    }
    public void NotifyObserver()
    {
        IEnumerator enumerator = observers.GetEnumerator();
        while (enumerator.MoveNext())
        {
            Observer observer = (Observer)enumerator.Current;
            observer.Update(duck);
        }
    }
}
cs

생성자의 인자로 QuackObservable 객체를 받아 처리합니다. 이제 구상 클래스에서 이것을 결합합니다.

public class MallardDuck : Quackable
{
    Observable observable;
    public MallardDuck()
    {
        observable = new Observable(this);
    }
    public void Quack()
    {
        Console.WriteLine("Quack");
        NotifyObservers();
    }
    public void RegisterObserver(Observer observer)
    {
        observable.RegisterObserver(observer);
    }
    public void NotifyObservers()
    {
        observable.NotifyObservers();
    }
}
cs


같은 식으로 다른 구상 클래스들도 고쳐줍니다.
Quackable이 바뀌었으므로 QuackCounter도 고쳐야 합니다.

public class QuackCounter : Quackable
{
    Quackable duck;
    static int numberOfQuacks;
    public QuackCounter(Quackable duck)
    {
        this.duck = duck;
    }
    public void Quack()
    {
        duck.Quack();
        numberOfQuacks++;
    }
    public static int GetQuacks()
    {
        return numberOfQuacks;
    }
    public void RegisterObserver(Observer observer)
    {
        duck.RegisterObserver(observer);
    }
    public void NotifyObservers()
    {
        duck.NotifyObservers();
    }
}
cs

아직 Quackable을 구현하는 것이 하나 더 남았습니다. Flock입니다.

public class Flock : Quackable
{
    List<Quackable> quackers = new List<Quackable>();
    public void Add(Quackable quacker)
    {
        quackers.Add(quacker);
    }
    public void Quack()
    {
        IEnumerator iterator = quackers.GetEnumerator();
        while (iterator.MoveNext())
        {
            Quackable quacker = (Quackable)iterator.Current;
            quacker.Quack();
        }
    }
    public void RegisterObserver(Observer observer)
    {
        IEnumerator iterator = quackers.GetEnumerator();
        while (iterator.MoveNext())
        {
            Quackable quacker = (Quackable)iterator.Current;
            quacker.RegisterObserver(observer);
        }
    }
    public void NotifyObservers() { }
}
cs


이제 옵저버 클래스를 만들어 줍니다. 꽥학자들이 그 역할을 합니다.
public class Quackologist : Observer
{
    public void Update(QuackObservable duck)
    {
        Console.WriteLine("꽥학자: 방금 꽥 거린 오리는" + duck + "입니다");
    }
}
cs

이제 모든 준비가 되었습니다. 시뮬레이터를 고치고 테스트 해 봅시다.

class DuckSimulator
{
    static void Main(string[] args)
    {
        DuckSimulator simulator = new DuckSimulator();
        AbstractDuckFactory duckFactory = new CountingDuckFactory();
        simulator.simulate(duckFactory);
    }
    void simulate(AbstractDuckFactory duckFactory)
    {            
         //  오리 팩토리와 오리 생성
         //  오리떼 생성
        Console.WriteLine("\nDuck Simulator: With Observer");
        Quackologist quackologist = new Quackologist();
        flockOfDucks.RegisterObserver(quackologist);
        Simulate(flockOfDucks);            
        Console.WriteLine("오리가 " + QuackCounter.GetQuacks() + "번 꽥꽥거렸습니다.");
    }
    void Simulate(Quackable duck)
    {
        duck.Quack();
    }
}
cs

결과)
Duck Simulator: With Observer
Quack
꽥학자: 방금 꽥 거린 오리는 Redhead Duck입니다
Kwak
꽥학자: 방금 꽥 거린 오리는 Duck Call입니다
Squeak
꽥학자: 방금 꽥 거린 오리는 Rubber Duck입니다
Honk
꽥학자: 방금 꽥 거린 오리는 오리인척 하는 거위입니다
Quack
꽥학자: 방금 꽥 거린 오리는 Mallard Duck입니다
Quack
꽥학자: 방금 꽥 거린 오리는 Mallard Duck입니다
Quack
꽥학자: 방금 꽥 거린 오리는 Mallard Duck입니다
Quack
꽥학자: 방금 꽥 거린 오리는 Mallard Duck입니다
오리가 7번 꽥꽥거렸습니다.
계속하려면 아무 키나 누르십시오 . . .

오리 소리 연구에 많은 패턴이 한데 들어 갔습니다. 이렇게 복합적으로 많은 패턴이 쓰였으므로 컴파운드(복합) 패턴이라고 합니다.

이런 컴파운드 패턴 가운데에서 가장 유명한 것이 MVC 패턴입니다. 책에는 너무 자바 위주로 되어있어 단순 적용 시키기 쉽지 않습니다. 그렇다고 대표적으로 MVC 패턴을 이용하는 스마트폰 앱 개발을 공부하는 주제에 그냥 넘어갈 수도 없으니 뭔가 좋은 예를 찾아 살펴 보고 넘어가야할 것 같습니다.

지금까지 작성한 전체 코드를 공개하고 다음 글에서 MVC를 알아보겠습니다.

using System;
using System.Collections;
using System.Collections.Generic;
 
namespace CompoundPattern
{
    // Quackble 인터페이스
    public interface Quackable : QuackObservable
    {
        void Quack();
    }
 
    // 오리 클래스
    public class MallardDuck : Quackable
    {
        Observable observable;
 
        public MallardDuck()
        {
            observable = new Observable(this);
        }
        public void Quack()
        {
            Console.WriteLine("Quack");
            NotifyObservers();
        }
 
        public void RegisterObserver(Observer observer)
        {
            observable.RegisterObserver(observer);
        }
 
        public void NotifyObservers()
        {
            observable.NotifyObservers();
        }
 
        public override string ToString()
        {
            return "Mallard Duck";
        }
    }
 
    public class RedheadDuck : Quackable
    {
        Observable observable;
 
        public RedheadDuck()
        {
            observable = new Observable(this);
        }
 
        public void Quack()
        {
            Console.WriteLine("Quack");
            NotifyObservers();
        }
 
        public void RegisterObserver(Observer observer)
        {
            observable.RegisterObserver(observer);
        }
 
        public void NotifyObservers()
        {
            observable.NotifyObservers();
        }
        public override string ToString()
        {
            return "Redhead Duck";
        }
    }
 
    public class DuckCall : Quackable
    {
        Observable observable;
 
        public DuckCall()
        {
            observable = new Observable(this);
        }
        public void Quack()
        {
            Console.WriteLine("Kwak");
            NotifyObservers();
        }
        public void RegisterObserver(Observer observer)
        {
            observable.RegisterObserver(observer);
        }
 
        public void NotifyObservers()
        {
            observable.NotifyObservers();
        }
        public override string ToString()
        {
            return "Duck Call";
        }
    }
 
    public class RubberDuck : Quackable
    {
        Observable observable;
 
        public RubberDuck()
        {
            observable = new Observable(this);
        }
        public void Quack()
        {
            Console.WriteLine("Squeak");
            NotifyObservers();
        }
 
        public void RegisterObserver(Observer observer)
        {
            observable.RegisterObserver(observer);
        }
 
        public void NotifyObservers()
        {
            observable.NotifyObservers();
        }
        public override string ToString()
        {
            return "Rubber Duck";
        }
    }
 
    // 거위 클래스
    public class Goose
    {
        public void Honk()
        {
            Console.WriteLine("Honk");
        }
    }
 
    // 거위 어댑터
    public class GooseAdapter : Quackable
    {
        Observable observable;
        Goose goose;
 
        public GooseAdapter(Goose goose)
        {
            this.goose = goose;
            observable = new Observable(this);
        }
 
        public void Quack()
        {
            goose.Honk();
            NotifyObservers();
        }
 
        public void RegisterObserver(Observer observer)
        {
            observable.RegisterObserver(observer);
        }
 
        public void NotifyObservers()
        {
            observable.NotifyObservers();
        }
        public override string ToString()
        {
            return "오리인척 하는 거위";
        }
    }
 
    // 데코레이터
    public class QuackCounter : Quackable
    {
        Quackable duck;
        static int numberOfQuacks;
 
        public QuackCounter(Quackable duck)
        {
            this.duck = duck;
        }
 
        public void Quack()
        {
            duck.Quack();
            numberOfQuacks++;
        }
 
        public static int GetQuacks()
        {
            return numberOfQuacks;
        }
 
        public void RegisterObserver(Observer observer)
        {
            duck.RegisterObserver(observer);
        }
 
        public void NotifyObservers()
        {
            duck.NotifyObservers();
        }
    }
 
    // 추상 팩토리
    public abstract class AbstractDuckFactory
    {
        public abstract Quackable CreateMallardDuck();
        public abstract Quackable CreateRedheadDuck();
        public abstract Quackable CreateDuckCall();
        public abstract Quackable CreateRubberDuck();
    }
 
    public class CountingDuckFactory : AbstractDuckFactory
    {
        public override Quackable CreateMallardDuck()
        {
            return new QuackCounter(new MallardDuck());
        }
        public override Quackable CreateRedheadDuck()
        {
            return new QuackCounter(new RedheadDuck());
        }
        public override Quackable CreateDuckCall()
        {
            return new QuackCounter(new DuckCall());
        }
        public override Quackable CreateRubberDuck()
        {
            return new QuackCounter(new RubberDuck());
        }
    }
 
    // 컴포짓 
    public class Flock : Quackable
    {
        List<Quackable> quackers = new List<Quackable>();
 
        public void Add(Quackable quacker)
        {
            quackers.Add(quacker);
        }
 
        public void Quack()
        {
            IEnumerator iterator = quackers.GetEnumerator();
            while (iterator.MoveNext())
            {
                Quackable quacker = (Quackable)iterator.Current;
                quacker.Quack();
            }
        }
 
        public void RegisterObserver(Observer observer)
        {
            IEnumerator iterator = quackers.GetEnumerator();
            while (iterator.MoveNext())
            {
                Quackable quacker = (Quackable)iterator.Current;
                quacker.RegisterObserver(observer);
            }
        }
 
        public void NotifyObservers() { }
    }
    
    // 옵저버 패턴
    public interface Observer
    {
        void Update(QuackObservable duck);
    }
 
    public interface QuackObservable
    {
        void RegisterObserver(Observer observer);
        void NotifyObservers();
    }
 
    public class Observable : QuackObservable
    {
        List<Observer> observers = new List<Observer>();
        QuackObservable duck;
 
        public Observable(QuackObservable duck)
        {
            this.duck = duck;
        }
 
        public void RegisterObserver(Observer observer)
        {
            observers.Add(observer);
        }
 
        public void NotifyObservers()
        {
            IEnumerator enumerator = observers.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Observer observer = (Observer)enumerator.Current;
                observer.Update(duck);
            }
        }
    }
 
    public class Quackologist : Observer
    {
        public void Update(QuackObservable duck)
        {
            Console.WriteLine("꽥학자: 방금 꽥 거린 오리는 " + duck + "입니다");
        }
    }
 
    //시뮬레이터
    class DuckSimulator
    {
        static void Main(string[] args)
        {
            DuckSimulator simulator = new DuckSimulator();
            AbstractDuckFactory duckFactory = new CountingDuckFactory();
            simulator.simulate(duckFactory);
        }
 
        void simulate(AbstractDuckFactory duckFactory)
        {            
            Quackable readheadDuck = duckFactory.CreateRedheadDuck();
            Quackable duckCall = duckFactory.CreateDuckCall();
            Quackable rubberDuck = duckFactory.CreateRubberDuck();
            Quackable gooseDuck = new GooseAdapter(new Goose());           
 
            Flock flockOfDucks = new Flock();
                        
            flockOfDucks.Add(readheadDuck);
            flockOfDucks.Add(duckCall);
            flockOfDucks.Add(rubberDuck);
            flockOfDucks.Add(gooseDuck);
 
            Flock flockOfMallards = new Flock();
 
            Quackable mallardOne = duckFactory.CreateMallardDuck();
            Quackable mallardTwo = duckFactory.CreateMallardDuck();
            Quackable mallardThree = duckFactory.CreateMallardDuck();
            Quackable mallardFour = duckFactory.CreateMallardDuck();
 
            flockOfMallards.Add(mallardOne);
            flockOfMallards.Add(mallardTwo);
            flockOfMallards.Add(mallardThree);
            flockOfMallards.Add(mallardFour);
 
            flockOfDucks.Add(flockOfMallards);
 
            Console.WriteLine("\nDuck Simulator: With Observer");
            Quackologist quackologist = new Quackologist();
            flockOfDucks.RegisterObserver(quackologist);
            Simulate(flockOfDucks);            
 
            Console.WriteLine("오리가 " + QuackCounter.GetQuacks() + "번 꽥꽥거렸습니다.");
        }
 
        void Simulate(Quackable duck)
        {
            duck.Quack();
        }
    }
}
 
cs

댓글 없음:

댓글 쓰기