SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

実例で学ぶ、コード品質の高め方

どうやってコード品質を上げるのか? 実例で学ぶリファクタリング

第3回 ステップ・バイ・ステップで学ぶC++コードのリファクタリング

ステップ3:既存のコードの置き換え

 次に、main内部のコードを新しい関数に置き換えてみます。例えば以下のようになるでしょう。

// 前半省略:ステップ2のコードと同じ

int main() {
    std::map<std::string, std::vector<double>> products = {
        {"T-Shirts", {29.99, 34.99, 24.99, 19.99}},
        {"Jeans", {49.99, 59.99, 69.99, 79.99}}
    };

    // ステップ3: 既存のコードを新しい関数に置き換える
   for (const auto& product : products) {
        double total, average;
        std::tie(total, average) = calculateTotalAndAverage(product.second);
        std::cout << "Total price of " << product.first << ": $" << total << std::endl;
        std::cout << "Average price of " << product.first << ": $" << average << std::endl;
    }

    return 0;
}

 今後productsが増えることを考慮し、T-Shirts、Jeansと処理を別々に書くのではなく、ループで回して計算・表示するようにしました。コードの修正が終わったら、すかさずコンパイル・テストを行いましょう。オリジナルやステップ2のコードと結果が変わらないことを確認してください。

ステップ4:再利用性を考慮して、コード分割

 実装したcalculateTotalAndAverageは、プロジェクト内の他のプログラムからも便利に使えそうです。再利用のため、コードを分割しましょう。具体的には以下のような手順で分割します。

1. 関数宣言をヘッダーファイルに移動

 calculateTotalAndAverage関数の関数宣言を新しいヘッダーファイル calculateTotalAndAverage.hに移動します。

2. 関数の実装をソースファイルに移動

 calculateTotalAndAverage関数の実装を新しいソースファイル calculateTotalAndAverage.cppに移動します。

3. main関数を含むファイルの更新

 main関数があるファイル(main.cppとします)から、新しいヘッダーファイル calculateTotalAndAverage.hをインクルードします。

 これにより、作成された3つのファイルはそれぞれ以下のようになります。

calculateTotalAndAverage.h
#ifndef CALCULATE_TOTAL_AND_AVERAGE_H
#define CALCULATE_TOTAL_AND_AVERAGE_H

#include <vector>
#include <utility>

std::pair<double, double> calculateTotalAndAverage(const std::vector<double>& prices);

#endif // CALCULATE_TOTAL_AND_AVERAGE_H
calculateTotalAndAverage.cpp
#include "calculateTotalAndAverage.h"

std::pair<double, double> calculateTotalAndAverage(const std::vector<double>& prices) {
    double total = 0.0;
    for (double price : prices) {
        total += price;
    }
    double average = prices.empty() ? 0.0 : total / prices.size();
    return {total, average};
}
main.cpp
#include <iostream>
#include <vector>
#include <map>
// ステップ3: calculateTotalAndAverage 関数を別ファイルにする
#include "calculateTotalAndAverage.h"

int main() {
    std::map<std::string, std::vector<double>> products = {
        {"T-Shirts", {29.99, 34.99, 24.99, 19.99}},
        {"Jeans", {49.99, 59.99, 69.99, 79.99}}
    };

   for (const auto& product : products) {
        double total, average;
        std::tie(total, average) = calculateTotalAndAverage(product.second);
        std::cout << "Total price of " << product.first << ": $" << total << std::endl;
        std::cout << "Average price of " << product.first << ": $" << average << std::endl;
    }
    return 0;
}

 すかさずコンパイル・テストをお願いします。ファイル分割した後のコンパイルは、各ソースファイル(.cppファイル)を個別にコンパイルしてから、それらをリンクして実行可能ファイルを作成するという手順になります。以下は、コマンド例です。

$ g++ -c -std=c++11 main.cpp -o main.o
$ g++ -c -std=c++11 calculateTotalAndAverage.cpp -o calculateTotalAndAverage.o
$ g++ main.o calculateTotalAndAverage.o -o myprogram
$ ./myprogram

 実行結果がステップ2、3のコードと同じであることを確認してください。口酸っぱく言ってしまってすみませんが、リファクタリングでは、こまめにコンパイル・テストすることが大事です。

次のページ
ステップ5:単体テストの追加

この記事は参考になりましたか?

実例で学ぶ、コード品質の高め方連載記事一覧

もっと読む

この記事の著者

浅原 明広(株式会社Sider)(アサハラ アキヒロ)

 日本IBM、株式会社フィックスターズなどで、半導体製造装置や医療画像機器など、大小様々な組み込み製品向けのソフトウェア開発プロジェクトに従事。 現在、フィックスターズ子会社の株式会社Sider にて、ソースコードのコピペ管理ツール『CloneTracker』を開発・提供。最新のツールや方法論を用いた、ソフトウェア開発者体験の向上に強い関心を持つ。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

千葉 滋(東京大学情報理工学系研究科教授)(チバ シゲル)

東京大学 情報理工学系研究科 創造情報学専攻 教授

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/18854 2024/01/18 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー