[실습으로 다지는 C#] 콘솔 응용의 기본 제어 – 메뉴로 상호 작용

이번 강의에서는 콘솔 응용에서 메뉴를 통해 프로그램의 흐름을 제어하는 실습을 해 볼 거예요.

콘솔 응용에서 사용자와 상호 작용을 담당하는 형식을 Application이라고 정의할게요.

class Application
{
}

Application 형식 개체는 하나만 존재하는 것이 맞겠죠. 단일체 패턴을 적용하기로 할게요.

 생성자의 접근 지정을 디폴트 값(private)으로 정하여 클래스 외부에서 개체 생성을 하지 못하게 막습니다. 그리고 정적 멤버로 클래스 외부에서 정적 개체를 참조할 수 있게 가져오기 속성을 제공합니다. 단일체는 정적 생성자에서 만드는 것을 추천합니다. 정적 생성자는 해당 형식을 사용하기 전에 수행하고 단 한 번만 수행하는 것을 보장하기 때문에 단일체를 생성하는 위치로 적당합니다.

    class Application
    {
        #region 단일체
        internal static Application Singleton 
        {
            get;
            private set;
        }
        static Application()
        {
            Singleton = new Application(); 
        }
        Application()
        {

        }
        #endregion 단일체
    }

 Application 개체에서는 초기화, 사용자와 상호 작용(실제 주요 프로그램 동작부), 해제화를 수행하는 세 개의 메서드를 외부 클래스에 제공할게요.

    class Application
    {
        ...중략...
        internal void Init()
        {
        }

        internal void Run()
        {
        }
        internal void Exit()
        {
        }
    }

 이번 실습에서 초기화와 해제화에서는 할 것이 특별히 없습니다. 차후에 초기화에서 파일에서 정보를 로딩하는 부분과 해제화에서 저장하는 등의 작업을 추가할 수 있을 것입니다.

 여기에서는 단순히 프로그램이 시작하고 끝난다는 것을 인지할 수 있는 정도의 작업만 추가하기로 할게요.

 해제화(Exit) 메서드에서 사용자가 마지막으로 아무 키나 누르면 종료할 수 있게 할게요. 이 때 Console.ReadLine 메서드는 적절치 않습니다.

 Console.ReadLine 메서드는 사용자로부터 정보를 입력받기 위한 메서드입니다. 따라서 입력 도중에 잘못 누른 것을 지울 수 있게 백스페이스 키를 제공합니다. 이는 입력이 끝났다는 의사 표현으로 엔터를 입력하게 하는 것이죠.

 아무 키나 누르면 바로 반응하는 메서드는 Console.ReadKey입니다. 입력 인자로 bool 형식 인자를 하나 받습니다. 만약 true를 전달하면 키를 눌렀을 때 콘솔 화면에 출력하지 않고 false를 누르면 콘솔 화면에 누른 키를 보여줍니다.

 여기에서는 단순히 흐름 제어를 위한 것이지 정보 입력을 위한 것이 아니므로 true를 전달할게요. 

    class Application
    {
        ...중략...
        internal void Init()
        {
            Console.WriteLine("콘솔 응용의 기본 제어 - 메뉴로 상호 작용");
            Console.WriteLine("아무 키나 누르면 시작합니다.");
            Console.ReadKey(true);
        }

        internal void Run()
        {
        }
        internal void Exit()
        {
            Console.WriteLine("아무 키나 누르시면 프로그램을 종료합니다.");
            Console.ReadKey(true);
        }
    }

 이제 사용자와 상호작용하에 프로그램 흐름을 제어할 Run 메서드를 작성합시다.

 전체 흐름은 종료 키를 선택할 때까지 선택한 키에 따라 함수를 수행하는 것을 반복하는 것입니다.

  
    class Application
    {
        ...생략...

        internal void Run()
        {
            //반복((키=메뉴 선택())!=종료키)
            {
                //선택한 키에 따라
                {
                    //키1 일 때: 메서드1 수행
                    //키2 일 때: 메서드2 수행
                    //키3 일 때: 메서드3 수행
                    //키4 일 때: 메서드4 수행
                    //키15일 때: 메서드5 수행
                    //다른 키: 잘못 선택한 것을 통보
                }
                //사용자가 결과 확인할 기회를 부여(아무 키나 누를 때까지 대기)
            }
        }
        ...생략...
    }
}

 사용자로부터 메뉴를 입력받을 때도 Console.ReadKey 메서드가 적절합니다. 다음은 메뉴 선택과 메서드1~메서드5까지 추가한 예제 코드입니다.

using System;

namespace 콘솔_응용_상호_작용_개요___메뉴
{    
    class Application
    {
        #region 단일체
        internal static Application Singleton
        {
            get;
            private set;
        }
        static Application()
        {
            Singleton = new Application(); 
        }
        Application()
        {
        }
        #endregion 단일체



        internal void Init()
        {
            Console.WriteLine("콘솔 응용의 기본 제어 - 메뉴로 상호 작용");
            Console.WriteLine("아무 키나 누르면 시작합니다.");
            Console.ReadKey(true);
        }

        internal void Run()
        {
            ConsoleKey key = ConsoleKey.NoName;
            while((key = SelectMenu())!= ConsoleKey.Escape)//반복((키=메뉴 선택())!=종료키)
            {
                switch(key) //선택한 키에 따라
                {
                    case ConsoleKey.F1: FunA(); break;//키1 일 때: 메서드1 수행
                    case ConsoleKey.F2: FunB(); break;//키2 일 때: 메서드2 수행
                    case ConsoleKey.F3: FunC(); break;//키3 일 때: 메서드3 수행
                    case ConsoleKey.F4: FunD(); break;//키4 일 때: 메서드4 수행
                    case ConsoleKey.F5: FunE(); break;//키15일 때: 메서드5 수행
                    default: Console.WriteLine("잘못 선택하였습니다."); break;//다른 키: 잘못 선택한 것을 통보
                }
                Console.WriteLine("아무 키나 누르세요.");
                Console.ReadKey(true);//사용자가 결과 확인할 기회를 부여(아무 키나 누를 때까지 대기)
            }
        }
        internal void Exit()
        {
            Console.WriteLine("아무 키나 누르시면 프로그램을 종료합니다.");
            Console.ReadKey(true);
        }

        private void FunE()
        {
            Console.WriteLine("FunE");
        }

        private void FunD()
        {
            Console.WriteLine("FunD");
        }

        private void FunC()
        {
            Console.WriteLine("FunC");
        }

        private void FunB()
        {
            Console.WriteLine("FunB");
        }

        private void FunA()
        {
            Console.WriteLine("FunA");
        }

        private ConsoleKey SelectMenu()
        {
            Console.Clear();
            Console.WriteLine("사용자와 상호 작용 개요 - 메뉴편");
            Console.WriteLine("{0}:FunA", ConsoleKey.F1);
            Console.WriteLine("{0}:FunB", ConsoleKey.F2);
            Console.WriteLine("{0}:FunC", ConsoleKey.F3);
            Console.WriteLine("{0}:FunD", ConsoleKey.F4);
            Console.WriteLine("{0}:FunE", ConsoleKey.F5);
            Console.WriteLine("종료를 원하시면 {0}를 누르세요.", ConsoleKey.Escape);
            return Console.ReadKey(true).Key;
        }
    }
}

 진입점에서는 Application 단일체를 참조한 후 초기화, 상호 작용, 해제화 순으로 진행합니다.

//https://ehpub.co.kr
//실습으로 다지는 C#
//콘솔 응용 메뉴를 통한 상호 작용 개요
namespace 콘솔_응용_상호_작용_개요___메뉴
{
    class Program
    {
        static void Main(string[] args)
        {
            Application app = Application.Singleton;
            app.Init();
            app.Run();
            app.Exit();
        }
    }
}