언어 자료구조 알고리즘/[C++]디딤돌 자료구조와 알고리즘

8. STL 실습 - 장르별 도서 관리 프로그램 [디딤돌 자료구조와 알고리즘 with C++]

언제나휴일 2016. 4. 4. 11:43
반응형

8. STL 실습 - 장르별 도서 관리 프로그램

이번 장에서는 STL에서 제공하는 vector, list, map을 사용하여 장르별 도서 관리 프로그램을 만들어 보아요.

 

실습할 프로그램에서는 도서를 장르별로 관리합니다. 장르에 도서는 vector를 이용하여 보관합니다. 응용에서는 장르를 list에 보관합니다. 그리고 App에는 모든 도서를 isbn(문자열 형식으로 정의)을 키로 값을 도서인 map에 보관합시다.

 

주의할 점은 하나의 도서 개체를 장르와 App에 보관할 것입니다. 똑같은 정보를 갖는 두 개의 도서 개체를 만들어서 보관할 것이 아님을 주의합시다.

 

시나리오는 다음과 같습니다.

 

주제: 장르별 도서 관리 프로그램

장르별 도서 관리 프로그램은 콘솔에서 동작하는 응용 프로그램입니다. 프로그램은 크게 초기화, 사용자와 상호 작용, 해제화 과정으로 수행합니다.

 

초기화 과정에서는 프로그램 시작에서 수행해야 할 초기 작업을 수행합니다. 필요한 작업이 없으면 생략하세요.

 

해제화 과정에서는 프로그램 종료할 때 수행해야 할 작업을 수행합니다. 필요한 작업이 없으면 생략하세요.

 

사용자 상호 작용에서는 메뉴를 출력하고 사용자가 메뉴를 선택하여 기능을 수행하는 것을 반복합니다. 사용자가 선택할 수 있는 메뉴는 장르 추가, 전체 장르 보기, 도서 추가, 도서 삭제, ISBN으로 도서 검색, 특정 장르 선택 후 도서 검색, 특정 장르 보기, 전체 도서 보기, 전체 보기가 있습니다.

 

장르 추가

생성할 장르의 일련 번호(1부터 순차 부여)를 보여주고 장르 이름을 입력받아 장르를 생성합니다.

장르는 응용 내의 장르 보관 리스트에 순차적으로 보관합니다.

 

전체 장르 보기

장르 번호 순서대로 모든 장르의 정보를 출력합니다.

 

도서 추가

도서 추가에서는 먼저 도서의 ISBN(주요 키, 문자열)을 입력받습니다.

같은 ISBN의 도서가 있으면 에러 문구를 출력하고 기능을 종료합니다.

추가할 장르를 선택한 후에 장르 내에 도서 구분자(1~100 사이의 정수)를 입력받습니다.

선택한 장르에 이미 추가한 도서의 구분자일 때는 에러 문구를 출력하고 기능을 종료합니다.

도서 제목을 입력받아 도서를 생성합니다.

생성한 도서는 장르 내의 벡터에 인덱스(도서 구분자 -1) 연산을 이용합니다.

그리고 응용 내의 도서 보관 맵에 ISBN 순으로 보관합니다.

 

도서 삭제

먼저 삭제할 도서가 있는 장르를 선택합니다.

그리고 장르 내 도서 구분자를 입력받습니다.

장르 내의 벡터에 인덱스(도서 구분자 -1) 연산을 이용하여 0으로 변경합니다.

응용 내의 도서 보관 맵에서 보관한 도서를 지웁니다.

그리고 도서 개체를 소멸합니다.

 

ISBN으로 도서 검색

검색할 도서의 ISBN을 입력합니다.

응용 내의 도서 보관 맵에서 도서를 검색하여 검색한 도서 정보를 출력합니다.

 

특정 장르 선택 후 도서 검색

장르를 선택합니다. 그리고 장르 내 도서 구분자를 입력받아 도서 정보를 출력합니다.

 

특정 장르 보기

먼저 장르를 선택합니다.

그리고 장르의 정보를 출력합니다.

장르 정보에는 장르 일련 번호, 장르 명과 장르 내에 보관한 모든 도서 정보입니다.

 

전체 도서 보기

응용 내의 도서 보관 맵에 보관한 모든 도서 정보를 출력합니다.

ISBN 순으로 도서 정보를 출력하였다면 정상적으로 작성한 것입니다.

 

전체 보기

모든 장르의 정보를 출력합니다. 여기에서는 장르 내에 보관한 도서 정보도 모두 출력합니다.

 

 

 

 

 

 

 

 

 

8.1 프로토 타이핑

구체적인 구현에 앞서 프로그램의 전체적인 흐름만 제어하는 프로토 타이핑을 해 보기로 해요.

 

콘솔 응용 프로젝트 템플릿으로 프로젝트를 생성하세요. 그리고 3.1.1에서 작성한 ehglobal.hehglobal.cpp 파일을 프로젝트 폴더에 복사한 후에 기존 항목으로 추가하세요.

 

그리고 진입점을 작성할 program.cpp 파일을 추가한 후에 비어있는 상태의 main함수를 작성하세요.

int main()

{

    return 0;

}

 

App, Genre, Book 클래스를 추가하세요.

 

여기에서는 프로토 타이핑만 할 것이며 App에서 메뉴를 선택하면 선택한 기능을 호출하는 부분까지만 구현할 거예요. 실무 프로그램에서 프로토 타이핑을 하는 이유는 이해 관계자의 요구 사항을 잘 파악하였는지 확인하기 위한 용도로 프로젝트 개발 초기 단계에서 프로토 타이핑을 합니다. 이해 관계자와 개발자는 지식 수준이나 사용하는 용어가 다르기 때문에 요구 분석을 잘못할 수 있습니다. 잘못 분석한 상태로 개발하는 것은 전체 개발 비용을 증가하는 요인으로 작용하기 때문에 제대로 분석한 것인지 확인하여 잘못 파악한 부분을 수정하여 제대로 이해 관계자의 요구 사항을 반영하기 위해 프로토 타이핑을 하는 것입니다.

 

먼저 Book.h 파일에 ehglobal.h를 포함하는 구문을 추가하세요.

#include "ehglobal.h"

class Book

{

public:

    Book(void);

    ~Book(void);

};

 

그리고 Genre.h 파일에 Book.hvector, algoritm을 포함하는 구문을 추가하세요.

#include "Book.h"

#include <vector>

#include <algorithm>

using namespace std;

 

그리고 Book *형식이 템플릿 인자인 vectorBooks 이름으로 타입 재지정합시다.

typedef vector<Book *> Books;

반복자도 타입 재지정하세요.

typedef Books::iterator BIter;

typedef Books::const_iterator CBIter;

 

 

Genre 클래스에 Books 형식 멤버 필드 books를 추가하세요.

class Genre

{

    Books books;

public:

    Genre(void);

    ~Genre(void);

};

 

App.h 파일에 Gerne.hlist, map을 포함하는 구문을 추가하세요.

#include "Genre.h"

#include <list>

#include <map>

using namespace std;

 

Genre *형식이 템플릿 인자인 listGenres 이름으로 타입 재지정하세요.

typedef list<Genre *> Genres;

반복자도 타입 재지정하세요.

typedef Genres::iterator GIter;

typedef Genres::const_iterator CGIter;

 

isbn을 키로 하기 위해 stringBook * 형식이 템플릿 인자인 mapBookDic으로 타입 재지정하세요.

typedef map<string, Book *> BookDic;

반복자도 타입 재지정하세요.

typedef BookDic::iterator BDIter;

typedef BookDic::const_iterator CBDIter;

 

App 클래스에 Genres 형식 genresBookDic 형식 bookdic 멤버 필드를 추가하세요.

class App

{

    Genres genres;

    BookDic bookdic;

public:

    App(void);

    ~App(void);

사용자와 상호 작용하는 Run 메서드를 추가하세요.

    void Run();

};

 

App.cpp 파일에도 Run 메서드를 빈 상태로 추가하세요.

void App::Run()

{

}

진입점 main에서는 App 개체를 생성하고 Run 메서드를 호출한 후에 소멸하는 코드를 작성하세요.

int main()

{

    App *app = new App();

    app->Run();

    delete app;

    return 0;

}

 

이제 AppRun 메서드를 작성합시다.

void App::Run()

{

    int key=NO_DEFINED;

사용자가 종료 메뉴를 선택하지 않으면 반복합니다.

    while((key = SelectMenu())!=ESC)//메뉴 출력 및 선택

    {

        switch(key)

        {

사용자가 입력한 키에 따라 약속한 기능을 호출하게 하세요.

        case F1: AddGenre(); break;//장르 추가

        case F2: ListGenre(); break; //전체 장르 보기

        case F3: AddBook(); break; //도서 추가

        case F4: RemoveBook(); break; //도서 삭제

        case F5: FindBookByISBN(); break; //ISBN으로 도서 검색

        case F6: FindBookAtAGenre(); break; //특정 장르 선택 후 도서 검색

        case F7: ViewAGenre(); break; //특정 장르 보기

        case F8: ListBook(); break; //전체 도서 보기

        case F9: ViewAll(); break; //전체 보기

        default: cout<<"잘못 선택하셨습니다."<<endl; break;

        }

수행한 작업을 확인할 수 있게 키를 입력해야 다시 메뉴 선택할 수 있게 하세요.

        cout<<"아무 키나 누르세요."<<endl;

        ehglobal::getkey();

    }

}

 

Run에서 작성한 메서드를 App 클래스의 멤버 메서드로 추가하세요. App.h 파일과 App.cpp 소스 파일 모두에 추가해야겠죠.

 

 

 

 

 

메뉴 출력 및 선택 기능을 구현하세요.

int App::SelectMenu()//메뉴 출력 및 선택   

{

이전에 출력한 내용을 지우세요.

    ehglobal::clrscr();

그리고 메뉴를 출력합니다.

    cout<<"장르별 도서 관리 프로그램 [ESC]종료"<<endl;

    cout<<"F1: 장르 추가 F2:전체 장르 보기"<<endl;

    cout<<"F3: 도서 추가 F4: 도서 삭제"<<endl;

    cout<<"F5: ISBN으로 도서 검색"<<endl;

    cout<<"F6: 특정 장르 선택 후 도서 검색"<<endl;

    cout<<"F7: 특정 장르 보기"<<endl;

    cout<<"F8: 전체 도서 보기 F9: 전체 보기"<<endl;

사용자로부터 입력받은 키를 반환하세요.

    return ehglobal::getkey();

}

다른 기능에서는 어떠한 기능을 선택했는지 확인할 수 있게 출력문을 작성하세요.

void App::AddGenre() //장르 추가

{

    cout<<"장르 추가"<<endl;

}

void App::ListGenre() //전체 장르 보기

{

    cout<<"전체 장르 보기"<<endl;

}

void App::AddBook()  //도서 추가

{

    cout<<"도서 추가"<<endl;

}

void App::RemoveBook() //도서 삭제

{

    cout<<"도서 삭제"<<endl;

}

void App::FindBookByISBN() //ISBN으로 도서 검색

{

    cout<<"ISBN으로 도서 검색"<<endl;

}

 

...중략...

 

 

 

 

다음은 프로토 타이핑에서 작성한 코드입니다.

//Program.cpp

#include "App.h"

int main()

{

    App *app = new App();

    app->Run();

    delete app;

    return 0;

}

 

//Book.h

#pragma once

#include "ehglobal.h"

class Book

{

public:

    Book(void);

    ~Book(void);

};

 

//Book.cpp

#include "Book.h"

 

Book::Book(void)

{

}

 

Book::~Book(void)

{

}

 

//Genre.h

#pragma once

#include "Book.h"

#include <vector>

#include <algorithm>

using namespace std;

 

typedef vector<Book *> Books;

typedef Books::iterator BIter;

typedef Books::const_iterator CBIter;

 

class Genre

{

    Books books;

public:

    Genre(void);

    ~Genre(void);

};

 

//Genre.cpp

#include "Genre.h"

Genre::Genre(void)

{

}

Genre::~Genre(void)

{

}

 

//App.h

#pragma once

#include "Genre.h"

#include <list>

#include <map>

using namespace std;

typedef list<Genre *> Genres;

typedef Genres::iterator GIter;

typedef Genres::const_iterator CGIter;

typedef map<string, Book *> BookDic;

typedef BookDic::iterator BDIter;

typedef BookDic::const_iterator CBDIter;

class App

{

    Genres genres;

    BookDic bookdic;

public:

    App(void);

    ~App(void);

    void Run();

private:

    int SelectMenu();//메뉴 출력 및 선택   

    void AddGenre(); //장르 추가

    void ListGenre(); //전체 장르 보기

    void AddBook();  //도서 추가

    void RemoveBook(); //도서 삭제

    void FindBookByISBN(); //ISBN으로 도서 검색

    void FindBookAtAGenre(); //특정 장르 선택 후 도서 검색

    void ViewAGenre(); //특정 장르 보기

    void ListBook(); //전체 도서 보기

    void ViewAll(); //전체 보기

};

 

//App.cpp

#include "App.h"

App::App(void)

{

}

App::~App(void)

{

}

void App::Run()

{

    int key=NO_DEFINED;

    while((key = SelectMenu())!=ESC)//메뉴 출력 및 선택

    {

        switch(key)

        {

        case F1: AddGenre(); break;//장르 추가

        case F2: ListGenre(); break; //전체 장르 보기

        case F3: AddBook(); break; //도서 추가

        case F4: RemoveBook(); break; //도서 삭제

        case F5: FindBookByISBN(); break; //ISBN으로 도서 검색

        case F6: FindBookAtAGenre(); break; //특정 장르 선택 후 도서 검색

        case F7: ViewAGenre(); break; //특정 장르 보기

        case F8: ListBook(); break; //전체 도서 보기

        case F9: ViewAll(); break; //전체 보기

        default: cout<<"잘못 선택하셨습니다."<<endl; break;

        }

        cout<<"아무 키나 누르세요."<<endl;

        ehglobal::getkey();

    }

}

int App::SelectMenu()//메뉴 출력 및 선택   

{

    ehglobal::clrscr();

    cout<<"장르별 도서 관리 프로그램 [ESC]종료"<<endl;

    cout<<"F1: 장르 추가 F2:전체 장르 보기"<<endl;

    cout<<"F3: 도서 추가 F4: 도서 삭제"<<endl;

    cout<<"F5: ISBN으로 도서 검색"<<endl;

    cout<<"F6: 특정 장르 선택 후 도서 검색"<<endl;

    cout<<"F7: 특정 장르 보기"<<endl;

    cout<<"F8: 전체 도서 보기 F9: 전체 보기"<<endl;

 

    return ehglobal::getkey();

}

void App::AddGenre() //장르 추가

{

    cout<<"장르 추가"<<endl;

}

void App::ListGenre() //전체 장르 보기

{

    cout<<"전체 장르 보기"<<endl;

}

void App::AddBook()  //도서 추가

{

    cout<<"도서 추가"<<endl;

}

void App::RemoveBook() //도서 삭제

{

    cout<<"도서 삭제"<<endl;

}

void App::FindBookByISBN() //ISBN으로 도서 검색

{

    cout<<"ISBN으로 도서 검색"<<endl;

}

void App::FindBookAtAGenre() //특정 장르 선택 후 도서 검색

{

    cout<<"특정 장르 선택 후 도서 검색"<<endl;

}

void App::ViewAGenre() //특정 장르 보기

{

    cout<<"특정 장르 보기"<<endl;

}

void App::ListBook() //전체 도서 보기

{

    cout<<"전체 도서 보기"<<endl;

}

void App::ViewAll() //전체 보기

{

    cout<<"전체 보기"<<endl;

}

반응형