단일체 패턴(Singleton Pattern)

최용국·2020년 2월 25일
0

디자인패턴

목록 보기
1/6

20-0225 SingletonPattern

코드를 짜다보면 클래스 인스턴스가 프로젝트에서 단 한번만 생성되기를 바랄 때가 있다.

다음예제는 text 파일을 출력하는 TextController라는 싱글 인스턴스가 있고 해당 인스턴스가 가지고 있는 자료구조(queue)에 멀티 쓰레드 환경(Parallel)에서 아이템(string)을 쌓으면 TextController 인스턴스가 Write 한다.

최초 한번은 10개씩 2번 총 20개의 아이템을 쌓는다. run 명령어를 입력하면 queue에 쌓는 행위를 반복하고 stop 명령어를 입력하면 write를 멈추고 Queue에 남은 값들을 보여주고 끝난다.

TextController Singleton 구현부분

public class TextController
{
    static TextController()
    {
        Instance = new TextController();
    }
    public static TextController Instance { get; private set; }
}
private TextController
{

}

TextController 전체

public class TextController
{
    static TextController()
    {
        Instance = new TextController();
    }
    public static TextController Instance { get; private set; }

    public string SourceFile => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "singleton.txt");

    public Queue<string> JobQueue { get; private set; } = new Queue<string>();

    private object jobQueueLock = new object();

    private string Dequeue()
    {
        lock (jobQueueLock)
        {
            if (JobQueue.Count != 0)
            {
                return JobQueue.Dequeue();
            }
            else
                return null;
        }
    }

    public void Enqueue(string contents)
    {
        lock (jobQueueLock)
        {
            JobQueue.Enqueue(contents);
        }
    }

    public void View()
    {
        lock (jobQueueLock)
        {
            foreach (var contents in JobQueue)
            {
                Console.WriteLine($"Queue 남은 값: {contents}");
            }
        }
    }

    private Task WriteTask { get; set; }
    private CancellationTokenSource WriteTaskCancelToken { get; set; } = new CancellationTokenSource();
    public void Start()
    {
        Console.WriteLine($"{nameof(TextController)} 파일생성");
        using (var fileStream = File.Create(this.SourceFile)) { }

        Console.WriteLine("Write Task 시작");
        WriteTask = Task.Factory.StartNew(() => Write(), this.WriteTaskCancelToken.Token);
    }


    private void Write()
    {
        while (!this.WriteTaskCancelToken.IsCancellationRequested)
        {
            var contents = Dequeue();
            if (!string.IsNullOrEmpty(contents))
            {
                using (var writer = new StreamWriter(File.Open(this.SourceFile, FileMode.Append, FileAccess.Write)))
                {
                    Console.WriteLine($"write : {contents}");
                    writer.WriteLine(contents);
                }
            }
            Thread.Sleep(1000);
        }
    }

    public void Stop()
    {
        this.WriteTaskCancelToken.Cancel();
    }
}

Program

class Program
{
    static void Main(string[] args)
    {
				//TextController single instance를 통해 메서드에 접근
				//singleton 사용
        TextController.Instance.Start();
        BulkEnqueue();
        while (true)
        {
            var command = Console.ReadLine();
            if (string.CompareOrdinal(command, "stop") == 0)
            {
                TextController.Instance.Stop();
                TextController.Instance.View();
                break;
            }
            else if (string.CompareOrdinal(command, "run") == 0)
            {
                BulkEnqueue();
            }
        }

    }

    static async void BulkEnqueue()
    {
        await Task.Factory.StartNew(() =>
        {
            foreach (var totalCount in Enumerable.Range(0, 2))
            {
                Parallel.ForEach(Enumerable.Range(0, 10), (index) =>
                {
                    var contents = $"ID: {Task.CurrentId}, totalCount: {totalCount}, index: {index}";
                    Console.WriteLine(contents);
                    TextController.Instance.Enqueue(contents);
                    Thread.Sleep(500);
                });
                Thread.Sleep(2000);
            }
        });
    }
}

결과

profile
코딩합시다.

0개의 댓글