5. 단일체 패턴(Singleton Pattern) 구현

단일체 패턴 프로젝트 다운로드

5. 4 구현

이제 단일체 패턴에 대한 예제 프로그램을 작성해 봅시다. 구현 순서는 메모리 카드, 내부 개체, 디스플레이 장치, 카메라 순으로 하겠습니다.

5.4.1 메모리 카드

메모리 카드에는 사진을 보관하는 메서드가 필요할 것입니다. 그리고 전체 사진의 개수를 확인하기 위한 속성과 특정 번호에 해당하는 사진을 얻어오는 인덱서를 제공하려고 합니다.

▶MemoryCard.cs

using System.Collections.Generic;

namespace Singleton
{
    class MemoryCard
    {
        List<string> pictures = new List<string>();

        public int PictureCount //사진의 개수
        {
            get
            {
                return pictures.Count;
            }
        }

        public int Store(string picture)
        {
            pictures.Add(picture);
            return PictureCount;
        }
        public string this[int index]
        {
            get
            {
                if ((index < 0) || (index >= PictureCount))
                {
                    return string.Empty;
                }
                return pictures[index];
            }
        }
    }
}


5.4.2
내부 개체

내부 개체는 단일체로 정의하였습니다. 단일체이므로 여러 개의 개체를 생성할 수 없게 생성자를 private으로 접근 지정할게요. 그리고 정적 생성자를 통해 단일체를 생성하게 하고 단일체를 얻어오기 위한 정적 멤버 속성을 제공합시다.

class InnerObject
{
    public static InnerObject Singleton
    {
        get;
    }
    static InnerObject();
    private InnerObject();
}

디자인 패턴을 구현하는 방법은 여러 가지가 있습니다. 여기에서 보여주는 방법은 여러 가지 방법의 하나일 뿐입니다.

이 외에도 내부 개체에는 카메라에 장착한 메모리 카드를 설정하는 메서드, 카메라로 찍은 사진을 메모리 카드에 보관하는 메서드, 메모리 카드에 보관된 전체 사진의 개수 및 현재 보고 있는 사진의 번호 등을 확인하기 위한 메서드와 속성들을 제공할 것입니다.

▶InnerObject.cs

namespace Singleton
{
    class InnerObject //단일체 클래스
    {
        MemoryCard memorycard =null;
        public int Now
        {
            get;
            private set;
        }
        public static InnerObject Singleton //단일체에 접근하기 위한 속성
        {
            get;
            private set;
        }
        static InnerObject() //단일체를 생성하는 정적 메서드
        {
            Singleton = new InnerObject();
        }
        private InnerObject() //단일체로 구현하기 위해 private으로 접근 지정
        {
            Now = 0;
        }
        public int PictureCount
        {
            get
            {
                return memorycard.PictureCount;
            }
        }
        public void PutMemoryCard(MemoryCard memorycard)
        {
            this.memorycard = memorycard;
        }
        public void StorePicture(string subject)
        {
            Now = memorycard.Store(subject);
        }
        public string NowPicture //현재 위치의 사진 
        {
            get
            {
                return memorycard[Now - 1];
            }
        }
        public void MoveBefore() //이전 사진으로 이동
        {
            if (Now > 1)
            {
                Now--;
            }
        }
        public void MoveNext() //다음 사진으로 이동
        {
            if (Now < PictureCount)
            {
                Now++;
            }
        }
    }
}

5.4.3 디스플레이 장치

디스플레이 장치는 사진 정보를 보여주는 기능을 약속하는 인터페이스 IView와 이를 기반으로 정의하는 InfoDisplay, PictureDisplay 클래스를 구현합시다.

▶IView.cs

namespace Singleton
{
    interface IView
    {
        void View();
    }
}

InfoDisplay와 PictureDisplay는 인터페이스에 약속한 View 메서드를 구현해야 합니다.

▶InfoDisplay.cs

using System;

namespace Singleton
{
    class InfoDisplay:IView
    {
        public void View()// IView에 약속한 메서드 구체적 구현 
        {
            InnerObject innerobj = InnerObject.Singleton;
            Console.WriteLine("정보 보기 모드");
            Console.WriteLine("전체 사진 수:{0}",innerobj.PictureCount);
            Console.WriteLine("현재 위치:{0}", innerobj.Now);
        }
    }
}

▶PictureDisplay.cs

using System;
namespace Singleton
{
    class PictureDisplay:IView
    {
        public void View()
        {
            InnerObject innerobj = InnerObject.Singleton;
            Console.WriteLine("사진 보기 모드");
            Console.WriteLine(innerobj.NowPicture);
        }
    }
}


5.4.4
카메라

카메라도 단일체로 정의를 하기로 하였습니다. 여러 개의 개체를 생성할 수 없게 생성자를 private으로 접근 지정하겠습니다. 그리고 단일체를 얻어오기 위한 정적 속성을 제공하고 정적 생성자에서 단일체 개체를 생성할게요.

class Camera
{
    public static Camera Singleton //단일체에 접근하기 위한 속성
    {
        get;
        private set;
    }
    static Camera() //단일체를 생성하는 정적 생성자
    {
        Singleton = new Camera();
    }
    private Camera()//단일체로 구현하기 위해 private로 접근 지정
    {
    }
}

그리고 카메라에는 메모리 카드를 장착하는 메서드와 사진을 찍는 메서드, 보기 모드를 전환하는 메서드 등을 제공합시다.

▶Camera.cs

namespace Singleton
{
    enum DisplayMode{ MODE_PICTURE, MODE_INFO }

    class Camera
    {
        InnerObject innerobj;
        DisplayMode displaymode;
        IView[] views = new IView[2];

        public static Camera Singleton //단일체에 접근하기 위한 속성
        {
            get;
            private set;
        }
        static Camera() //정적 생성자에서 단일체 생성
        {
            Singleton = new Camera();
        }

        private Camera() //단일체로 구현하기 위해 private으로 접근 지정
        {
            innerobj = InnerObject.Singleton;
            displaymode = DisplayMode.MODE_PICTURE;
            views[(int)DisplayMode.MODE_INFO] = new InfoDisplay();
            views[(int)DisplayMode.MODE_PICTURE] = new PictureDisplay();
        }

        public void PutMemoryCard(MemoryCard memorycard)
        {
            innerobj.PutMemoryCard(memorycard);	
        }
        public void TakeAPicture(string subject)
        {
            innerobj.StorePicture(subject);
        }
        public void View()
        {
            int vindex = (int)displaymode;
            views[vindex].View();
        }
        public void BeforePicture()
        {
            innerobj.MoveBefore();
        }
        public void NextPicture()
        {
            innerobj.MoveNext();
        }
        public void SetDisplayMode(DisplayMode displaymode)
        {
            this.displaymode = displaymode;
        }
    }
}

다음의 코드는 확인하기 위해서 작성된 코드입니다.

▶Program.cs

namespace Singleton
{
    class Program
    {
        static void Main(string[] args)
        {
            Camera camera = Camera.Singleton;
            MemoryCard mc = new MemoryCard();

            camera.PutMemoryCard(mc);
            camera.TakeAPicture("홍길동");
            camera.TakeAPicture("강감찬");

            ViewMode(camera);
            ViewPicture(camera);

            camera.BeforePicture();
            ViewMode(camera);
            ViewPicture(camera);
            
            camera.NextPicture();
            ViewPicture(camera);
        }

        private static void ViewMode(Camera camera)
        {
            camera.SetDisplayMode(DisplayMode.MODE_INFO);
            camera.View();
        }
        private static void ViewPicture(Camera camera)
        {
            camera.SetDisplayMode(DisplayMode.MODE_PICTURE);
            camera.View();
        }
    }
}

▶실행 결과

정보 보기 모드
전체 사진 수:2
현재 위치:2
사진 보기 모드
강감찬
정보 보기 모드
전체 사진 수:2
현재 위치:1
사진 보기 모드
홍길동
사진 보기 모드