CodeZine(コードジン)

特集ページ一覧

ラムダ式でステップアップ! C++のプログラムから汎用的なアルゴリズムを切り出し利用してみよう

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2014/09/25 14:00

目次

3. アルゴリズムを関数として分離

 前述のプログラムをよく眺め、中のアルゴリズムについて考えてみましょう。

 ProgramクラスのRun関数の中には、アルゴリズムが隠れています。例えば、次の2つです。

  • 書籍のリストの中から、「書籍のタイトルまたは出版社の名前に "リ" を含むもの」を抽出する
  • 書籍リストのそれぞれの書籍を表示する

 この2つのアルゴリズムを関数として分離してみましょう。リファクタリングの始まりです。

Run 関数から2つの関数を分離したメイン プログラム

Program.cpp
#include <iostream>
#include <list>
#include <vector>
#include <string>
using namespace std;

#include "Book.h"
#include "Publisher.h"

class Program
{
public:
    void Run()
    {
        const vector<Publisher> publisherList = {
            Publisher(L"技術評論社"          ),
            Publisher(L"翔泳社"              ),
            Publisher(L"オライリー・ジャパン"),
            Publisher(L"SBクリエイティブ"    )
        };

        const list<Book> bookList = {
            Book(L"4774157155", L"C++ ポケットリファレンス"        , 0),
            Book(L"4798108936", L"C++ の絵本"                      , 1),
            Book(L"4798119768", L"独習 C++ 第4版"                  , 1),
            Book(L"4873110637", L"C++ プログラミング入門"          , 2),
            Book(L"4797376686", L"C++ テンプレートテクニック 第2版", 3)
        };

        const list<Book> filteredBookList = Filter(bookList, publisherList);
        Show(filteredBookList, publisherList);
    }

private:
    // 書籍のリストの中から、
    // 「書籍のタイトルまたは出版社の名前に "リ" を含むもの」を抽出する。
    static list<Book> Filter(const list  <Book     >& bookList     ,
                             const vector<Publisher>& publisherList)
    {
        const wstring searchWord = L"リ";
        list<Book>    filteredBookList;

        for (list<Book>::const_iterator iterator = bookList.begin();
            iterator != bookList.end(); iterator++) {
            const wstring publisherName =
                publisherList[iterator->GetPublisherIndex()].GetName();
            if (iterator->GetTitle().find(searchWord) != wstring::npos ||
                publisherName.find(searchWord) != wstring::npos)
                filteredBookList.push_back(*iterator);
        }
        return filteredBookList;
    }

    // 書籍リストのそれぞれの書籍を表示する。
    static void Show(const list  <Book     >& bookList     ,
                     const vector<Publisher>& publisherList)
    {
        for (list<Book>::const_iterator iterator = bookList.begin();
             iterator != bookList.end(); iterator++) {
            wcout << L"コード: "     << iterator->GetCode ()
                  << L", タイトル: " << iterator->GetTitle()
                  << L", 出版社: "
                  << publisherList[iterator->GetPublisherIndex()].GetName()
                  << endl;
        }
    }
};

int main()
{
    wcout.imbue(locale("Japanese", locale::ctype));
    Program().Run();
    return 0;
}

 実行結果は同じです。

実行結果
コード: 4774157155, タイトル: C++ ポケットリファレンス, 出版社: 技術評論社
コード: 4873110637, タイトル: C++ プログラミング入門, 出版社: オライリー・ジャパン
コード: 4797376686, タイトル: C++ テンプレートテクニック 第2版, 出版社: SBクリエイティブ

 ここで、Run関数に注目してみましょう。

 記述が明快になりました。

  1. 書籍のリストの中から、「書籍のタイトルまたは出版社の名前に "リ" を含むもの」を抽出し、
  2. それを表示する

という意図の部分だけがRun関数に記述されるようになり、forだとかiteratorのような意図以外の部分の記述がなくなって、分かりやすくなりました。

 元の混沌としたRun関数から、書籍のリストに関して「抽出(Filter)」と「表示(Show)」という2つの部分を別関数として分けたためです。

 これは重要なことです。

 関数2つを分離したということは、「抽出(Filter)」や「表示(Show)」という名前でそれぞれの関心事を切り分けたことになります。そして、その「抽出(Filter)」と「表示(Show)」という新たな語彙でRun関数が記述できるようになった、ということです。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

修正履歴

  • 2014/10/14 16:20 姉妹記事「ラムダ式でステップアップ! C#のプログラムから汎用的なアルゴリズムを切り出すことで、LINQについての理解を深めよう」の紹介を第一節に挿入しました。

  • 2014/09/18 16:20 第8章のソースコード中の「// Sample.cpp」という不要な行を削除。

著者プロフィール

  • 小島 富治雄(フジヲ)

    Microsoft MVP for C# (2005.07~)。 - 注目の MVP - Blog: プログラミング C# - 翔ソフトウェア (Sho's) - Web Site: 翔ソフトウェア (Sho's) - Twitter: Fujiwo...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5