언어 자료구조 알고리즘/Escort C#

[C#] 7.4 프로젝트 구현 - 초점이 강의실 (판서 강의, 발표 수업)

언제나휴일 2016. 5. 3. 13:45
반응형

7.4 프로젝트 구현

 

초점이 강의실 (판서 강의, 발표 수업)


판서 강의 시퀀스 다이어그램

[그림] 판서 강의 시퀀스 다이어그램


 이번에는 초점이 강의실에 왔을 때에 수행하는 판서 강의와 발표 수업에 대해 구현해 보기로 합시다. 먼저, 초점이동이 되었을 때 수행하는 MoveFocusAt 메서드를 구현합시다. 여기에서는 입력 인자로 전달된 장소가 어디인지에 따라 각각의 장소에 초점이 왔을 때 수행하는 메서드를 호출하면 되겠네요.

 

class CampusLife

{

    ... 중략 ...

    private void MoveFocusAt(Place place)

    {

        if (place is LectureRoom)

        {

            FocusAtLectureRoom(place as LectureRoom);

        }

        if (place is Library)

        {

            FocusAtLibrary(place as Library);

        }

        if (place is Dormitory)

        {

            FocusAtDormitory(place as Dormitory);

        }

    }

    private void FocusAtDormitory(Dormitory dormitory)

    {        throw new NotImplementedException();    }

    private void FocusAtLibrary(Library library)

    {

        throw new NotImplementedException();

    }

    private void FocusAtLectureRoom(LectureRoom lectureRoom)

    {

        throw new NotImplementedException();

    }

}

 

 이 중에 강의실에 초점이 왔을 때 수행하는 FocusAtLectureRoom을 구현해 봅시다. 여기에서는 다시 강의실에서 수행할 수 있는 메뉴를 화면에 출력하여 사용자가 원하는 기능을 수행할 수 있게 해야 할 것입니다.

class CampusLife

{

    ... 중략 ...

    private void FocusAtLectureRoom(LectureRoom lectureRoom)

    {

        ConsoleKey key;

        while ((key = SelectLRMenu()) != GameRule.ExitKey)

        {

            switch (key)

            {

                case GameRule.LR_Forwarding: StartForwading(lectureRoom); break;

                case GameRule.LR_Announce: StartAnnounce(lectureRoom); break;

                default: Console.WriteLine("잘못된 메뉴를 선택하였습니다."); break;

            }

            Console.WriteLine("아무키나 누르세요.");

            Console.ReadKey();

        }

    }

    private void StartAnnounce(LectureRoom lectureRoom)

    {        throw new NotImplementedException();    }

    private void StartForwading(LectureRoom lectureRoom)

    {        throw new NotImplementedException();    }

    private ConsoleKey SelectLRMenu()

    {

        Console.Clear();

        Console.WriteLine("강의실 메뉴");

        Console.WriteLine("{0} 판서 강의", GameRule.LR_Forwarding);

        Console.WriteLine("{0} 발표 수업", GameRule.LR_Announce);

        Console.WriteLine("{0} 캠퍼스 생활로 돌아가기", GameRule.ExitKey);

        return Console.ReadKey().Key;

    }

}

 

 그리고 강의실 메뉴에서 사용하는 메뉴 키에 대한 상수를 GameRule에 정의해야겠지요. 미리 도서관과 기숙사에서 필요한 메뉴 키에 대한 상수도 정의를 할게요.

 

static class GameRule

{

    ... 중략 ...

    internal const ConsoleKey LR_Forwarding = ConsoleKey.F1;

    internal const ConsoleKey LR_Announce = ConsoleKey.F2;

 

    internal const ConsoleKey LI_Seminar = ConsoleKey.F1;

    internal const ConsoleKey LI_Reading = ConsoleKey.F2;

 

    internal const ConsoleKey DO_Sleep = ConsoleKey.F1;

    internal const ConsoleKey DO_TV = ConsoleKey.F2;

}

 


발표 수업 시퀀스 다이어그램

[그림] 발표 수업 시퀀스 다이어그램


 이제 판서 강의를 구현합시다. 판서 강의에 대한 시퀀스 다이어그램을 보면 캠퍼스 생활에서는 강의실에 판서 강의를 선택하였다는 것을 입력 인자로 전달하며 DoIt 메서드를 호출하게 약속하였죠. 이는 향후 시나리오가 변경되어 강의실에서 할 수 있는 기능이 추가될 경우를 고려한 것입니다. 이에 캠퍼스 생활에서는 다음과 같이 호출하면 될 것입니다.

 

class CampusLife

{

    ... 중략 ...

    private void StartForwading(LectureRoom lectureRoom)

    {

        lectureRoom.DoIt(GameRule.CMD_LR_Forwarding);

    }

}

  

 마찬가지로 각 장소에 사용자가 선택한 기능이 무엇인지에 대한 상수도 GameRule에 정의를 하도록 합시다.

 

static class GameRule

{

   ... 중략 ...

    internal const int CMD_LR_Forwarding = (int)LR_Forwarding;

    internal const int CMD_LR_Announce = (int)LR_Announce;

    internal const int CMD_LI_Seminar = (int)LI_Seminar;

    internal const int CMD_LI_Reading = (int)LI_Reading;

    internal const int CMD_DO_Sleep = (int)DO_Sleep;

    internal const int CMD_DO_TV = (int)DO_TV;

}

 

 현재 시나리오에는 LectureRoom에 입력 인자로 cmd 하나가 오는 DoIt 메서드는 판서 강의만 있습니다. 하지만 시나리오의 변경이 있을 수 있으니 선택문으로 판서 강의를 하는 것으로 구현하겠습니다. 판서 강의에서는 강의실에 모든 학생에게 강의를 듣게 하는 것과 해당 학생이 진취적인 학생일 경우 질문을 하는 것으로 되어 있습니다. 이에 각 장소의 기반 클래스인 Place에 특정 인덱스에 해당하는 학생을 참조할 수 있는 GetStudent메서드를 제공하고 이에 대한 접근 지정을 protected로 지정하겠습니다.

 

abstract class Place

{

   ... 중략 ...

    protected Student GetStudent(int nth)

    {

        int cnt = GetStuCount();

        if ((nth >= 0) && (nth < cnt))

        {

            return students[nth];

        }

        return null;

    }

}

  

class LectureRoom:Place

{

    ... 중략 ...

    internal override void DoIt(int cmd)

    {

        switch (cmd)

        {

            case GameRule.CMD_LR_Forwarding: StartForwarding(); break;

            default: return;

        }

   }

 

    private void StartForwarding()

    {

        int cnt = GetStuCount();

        Student student = null;

        CStudent cstudent = null;

 

        for (int i = 0; i < cnt; i++)

        {

            student = GetStudent(i);

            student.ListenLecture();

            cstudent = student as CStudent;

            if (cstudent != null)

            {

                cstudent.Question();

            }

        }

    }

}

  

  이제 Student 클래스에 ListenLecture 메서드를 구현해 봅시다. 시나리오를 보시면 강의를 들으면 학생의 아이큐가 5올라가고 HP 4내려가고 CP 1내려가는 것으로 되어 있습니다. 이를 반영하기 위해 Student에 멤버 필드로 iq hp, cp를 추가하고 이를 얻어오거나 설정하는 멤버 속성을 추가하겠습니다. 또한, 이들의 최대값과 최소값, 초기값이 약속되어 있는데 이는 정적 클래스 StudentValueDefine을 추가하여 상수 멤버를 이용하기로 하겠습니다.

 

static class StudentValueDefine

{

    internal const int MinIq = 60;

    internal const int MaxIq = 200;

    internal const int DefIq = 80;

 

    internal const int MinHp = 0;

    internal const int MaxHp = 100;

    internal const int DefHp = 50;

 

    internal const int MinCp = 0;

    internal const int MaxCp = 100;

    internal const int DefCp = 0;

}

 

class Student

{

    ... 중략 ...

 

    int iq;

    int hp;

    int cp;

 

    public int Iq

    {

        get

        {

            return iq;

        }

        protected set

        {

            if (value < StudentValueDefine.MinIq)

            {

                 value = StudentValueDefine.MinIq;

            }

            if (value > StudentValueDefine.MaxIq)

            {

                value = StudentValueDefine.MaxIq;

            }

            iq = value;

        }

    }

 

    public int Hp

    {

        get

        {

            return hp;

        }

        protected set

        {

            if (value < StudentValueDefine.MinHp)

            {

                 value = StudentValueDefine.MinHp;

            }

            if (value > StudentValueDefine.MaxHp)

            {

                value = StudentValueDefine.MaxHp;

           }

            hp = value;

        }

    }

 

 

    public int Cp

    {

        get

        {

            return cp;

        }

        protected set

        {

            if (value < StudentValueDefine.MinCp)

            {

                value = StudentValueDefine.MinCp;

            }

            if (value > StudentValueDefine.MaxCp)

            {

                value = StudentValueDefine.MaxCp;

            }

            cp = value;

        }

    }

    internal void ListenLecture()

    {

        Console.WriteLine("{0} 아이큐:{1} 체력:{2} 대화능력:{3}",ToString(),Iq,Hp,Cp);

        Console.WriteLine("강의를 듣다.");

        Iq += 5;

        Hp -= 4;

        Cp -= 1;

        Console.WriteLine("{0} 아이큐:{1} 체력:{2} 대화능력:{3}", ToString(), Iq, Hp, Cp);

    }

}

  

 도전적인 학생이 질문하는 Question 메서드는 시나리오에 있는 것처럼 아이큐와 대화능력을 변경하면 되겠죠.

 

class CStudent:Student

{

    ... 중략 ...

    internal void Question()

    {

        Console.WriteLine("{0} 아이큐:{1} 체력:{2} 대화능력:{3}",ToString(),Iq,Hp,Cp);

        Console.WriteLine("질문을 하다.");

        Iq += 1;

        Cp += 1;

        Console.WriteLine("{0} 아이큐:{1} 체력:{2} 대화능력:{3}",ToString(),Iq,Hp,Cp);

    }

}

 

 이번에는 강의실에 초점이 온 상태에서 발표 수업을 선택하였을 때 수행하는 캡퍼스 생활의 StartAnnounce 메서드를 구현해 보기로 합시다. 발표 수업에 대한 시퀀스 다어이그램을 보시면 강의실에 있는 학생들 정보를 보여준 다음 발표할 학생 번호를 입력받아 발표 수업을 선택한 것과 학생 번호를 입력 인자로 강의실 개체에 DoIt 메서드를 호출하게 되어 있습니다.

 

class CampusLife

{

    ... 중략 ...

    private void StartAnnounce(LectureRoom lectureRoom)

    {

        ViewStuInfoInPlace(lectureRoom);

        Console.WriteLine("발표할 학생 번호를 입력하세요. ");

        int num = EHLib.GetNum();

        lectureRoom.DoIt(GameRule.CMD_LR_Announce, num);

    }

}

  

 강의실에 두 개의 입력 인자를 전달받는 DoIt 메서드를 구현해 봅시다. DoIt 메서드에서는 입력 인자로 전달받은 학생 번호에 해당하는 학생이 존재하는지를 확인하는 것이 우선일 것입니다. 그리고 발표자는 발표를 진행하고 나머지 학생들은 자유 토론을 하도록 하면 되겠죠.

 

class LectureRoom:Place

{

    ... 중략 ...

    internal override void DoIt(int cmd, int snum)

    {

        Student student = this[snum];

        if (student == null)

        {

            Console.WriteLine("{0}번 학생은 없습니다.", snum);

            return;

        }

        switch (cmd)

        {

            case GameRule.CMD_LR_Announce: StartAnnounce(student); break;

            default: return;

        }

    }

    private void StartAnnounce(Student student)

    {

        student.Announce();

        int cnt = GetStuCount();

        Student stu = null;

        for (int i = 0; i < cnt; i++)

        {

            stu = GetStudent(i);

            if (stu != student){    stu.Discuss();    }

        }

    }

}

  

 이제 Student 클래스에 Announce 메서드와 Discuss 메서드를 구현합시다. 이 부분은 시나리오에 나온 것처럼 학생의 각 능력치를 변경하게 하면 될 것입니다. 참고로 자유 토론에 해당하는 Discuss에서는 시나리오에 어떠한 능력을 어떻게 변경하라는 것이 명시되어 있지 않으니 단순히 화면에 출력만 하도록 합시다.

 

class Student

{

    ... 중략 ...

    internal void Announce()

    {

        Console.WriteLine("{0} 아이큐:{1} 체력:{2} 대화능력:{3}", ToString(), Iq, Hp, Cp);

        Console.WriteLine("발표를 하다.");

        Cp+=3;

        Hp-=2;

        Console.WriteLine("{0} 아이큐:{1} 체력:{2} 대화능력:{3}", ToString(), Iq, Hp, Cp);

    }

    internal void Discuss()

    {

        Console.WriteLine("{0} 자유 토론을 하다.", ToString());

    }

}


 너와 나의 연결고리 "공감"

반응형