20-0406 Delegate Chain

최용국·2020년 4월 6일
0

관용구

목록 보기
5/9

20-0406 Delegate Chain

대리자 Delegate의 멀티 캐스트 기능을 활용해 Observer Pattern을 구현할 수 있다. 그 방법이 Delegate Chain이다 Chain 처럼 하나의 대리자에 여러개의 함수가 엮여있다 라고 생각하면 편하다.

다음 예제는 Thread 3개가 있고 Thread 3개를 안전하게 종료하기 위해 Stop 함수를 제공한다. 3개의 Thread Stop을 관리하는 Manager 싱글 인스턴스가 있고 Console창에 stop을 입력하면 Thread 3개가 안전하게 멈추고 프로그램이 종료된다.

interface IStop

public interface IStop
{
    void Stop();
}

class ThreadInstance

public class ThreadInstance : IStop
{
    private ThreadInstance()
    {
        IsStop = false;
    }

    public bool IsStop { get; set; }

    public Thread Thread { get; set; }

    public int Milisecond { get; set; }
    public string Id { get; set; }

    public static ThreadInstance AsRun(string id, Func<int, bool> execute, int milisecond)
    {
        ThreadInstance instance = new ThreadInstance();
        instance.Milisecond = milisecond;
        instance.Id = id;
        instance.Thread = new Thread(() => instance.Run(execute, instance));
        instance.Thread.Start();

        return instance;
    }

    private void Run(Func<int, bool> execute, ThreadInstance instance)
    {
        int index = 1;
        while (!IsStop)
        {
            if(execute.Invoke(index))
            {
                Console.WriteLine($"[{instance.Id} call]");
            }
            index++;
            Thread.Sleep(this.Milisecond);
        }

        Console.WriteLine($"[{instance.Id}] stopped");
    }

    public void Stop()
    {
        IsStop = true;
        while (this.Thread.ThreadState != ThreadState.Stopped)
        {
            Thread.Sleep(10);
        }
    }
}

class StopManager

public class StopManager
{
    private StopManager()
    {
    }

    static StopManager()
    {
        Instance = new StopManager();
    }

    public static StopManager Instance { get; }

    private delegate void StopDelegate();

    private StopDelegate StopChain
    {
        get;
        set;
    }

    public void Add(IStop stop)
    {
        StopChain += StopChain is null ? new StopDelegate(stop.Stop) : stop.Stop;
    }


    public void StopAll()
    {
        List<Task> stopTasks = new List<Task>();

        foreach (var stopDelegate in StopChain.GetInvocationList())
        {
            stopTasks.Add(Task.Factory.StartNew(() => stopDelegate.DynamicInvoke()));
            Delegate.Remove(StopChain, stopDelegate);
        }

        Task.WaitAll(stopTasks.ToArray());
    }
}

Program

class Program
{
    static void Main(string[] args)
    {
        var first = ThreadInstance.AsRun("최용국", index =>
        {
            if (index % 11 == 0)
            {
                Console.Write($"{index} 초!!! ");
                return true;
            }
            return false;
        }, 1000);

        var second = ThreadInstance.AsRun("이은혜", index =>
        {
            if (index % 7 == 0)
            { 
                Console.Write($"{index} 초!!! ");
                return true;
            }
            return false;
        }, 1000);

        var third = ThreadInstance.AsRun("도로시", index =>
        {
            if (index % 9 == 0)
            { 
                Console.Write($"{index} 초!!! ");
                return true;
            }
            return false;
        }, 1000);

        StopManager.Instance.Add(first);
        StopManager.Instance.Add(second);
        StopManager.Instance.Add(third);

        while (true)
        {
            var command = Console.ReadLine();
            if (command == "stop")
            {
                StopManager.Instance.StopAll();
                break;
            }
        }

        Console.WriteLine("press any key please");
        Console.ReadLine();
    }
}

결과

profile
코딩합시다.

0개의 댓글