2014/07/19

【C#】マジックナンバーを駆逐してやる!定数クラスの作り方


マジックナンバー(あいつ)ら......駆逐してやる!

このプロジェクトから......ひとつ残らず!


そんな感情をむき出しにしてしまうほど、マジックナンバーというやつに憎悪を感じる。
正確には、なんの躊躇もなくマジックナンバーを使うプログラマに憎悪を感じている。

そもそもマジックナンバーとは以下のようなものだ。


プログラムにおけるマジックナンバー(魔法数字)とは、何らかの識別子として用いられるプログラム中に書かれた具体的な数値である。そのプログラムを書いた時点では製作者は数値の意図を把握しているが、他のプログラマーまたは製作者本人がマジックナンバーの意図を忘れたとき閲覧すると「この数字の意味はわからないが、とにかくプログラムは正しく動く。まるで魔法の数字だ」という皮肉を含む。
引用元:マジックナンバー (プログラム) - Wikipedia


例えば以下のようなソースがあたったとする。
if (taxCalcKbn == "1")
{
    tax = price / 21;
    payment = price - tax;
}

さて、何をやっているんだろう?
if文の"1"はなんだろうか?なんでpriceを"21"で割っているんだろうか?
taxCalcKbnやtax、priceなどの変数から消費税の計算に関するものだと予想されるが……。


こういうソースばかりだと、プログラマは疲弊してしまう。


定数クラスをつくる


ソースの一番上に定数をまとめるのも良いが、先の例のようにプロジェクト全体使う場合は、定数クラスをつくろう。
// 定数クラス
public static class CommonConstants
{
    <summary>税計算区分</summary>
    public static class TaxCalcKbn
    {
        <summary>非課税</summary>
        public static readonly string EXEMPT = "0";
        <summary>内税</summary>
        public static readonly string INCLUDED = "1";
        <summary>外税</summary>
        public static readonly string EXCLUDED = "2";
    }
}

// メイン処理
if (CommonConstants.TaxCalcKbn.INCLUDED.equals(taxCalcKbn))
{
    tax = price * (rate / rate + 100);
    payment = price - tax;
}

こんな感じに書けば意味が伝わるだろう。
定数名かから「内税の場合」なんだろうと予測ができる。
また、if文内部の処理も、見た感じ税抜き金額を求めているだろうとわかる。



定数化しなくてもよいもの


定数には例外がある。
  • 一度しか使わないもの
  • テスト用ソースの中身
  • 定数化しなくても意味がわかるもの

これらは、付近にコメントを付けてあげるだけで十分。
具体的に作ってはいけない定数は、以下のようなものが挙げられる。
実にアホっぽい。
public static readonly int ZERO = 0;
public static readonly char SPACE = ' ';



巨大な定数クラスはつくるな


何も考えずに定数を追加していくと、いつの間にか巨大な定数クラスができてしまう。
以下の様な定数クラスがあったらどうだろうか?
public static class CommonConstants
{
    public static readonly string EXEMPT = "0";
    public static readonly string INCLUDED = "1";
    public static readonly string EXCLUDED = "2";
    public static readonly string ERROR_NOT_FOUND = "ERR001";
    public static readonly string ERROR_NOT_AVAILABLE = "ERR002";
    public static readonly string ERROR_UNDEFINED = "ERR003";
    public static readonly string INFO_MSG_001 = "確認してください。";
    public static readonly string WARN_MSG_001 = "上限を超えています。";
    public static readonly int WINDOW_X = 480;
    public static readonly unt WINDOW_Y = 640;
    // ~以降も延々と続く
}

こんなごちゃ混ぜな定数クラスの中から、必要な定数を見るけるのは困難だろう。

じゃぁ、どうすればよいのか。
こうしよう!
  • 種類ごとに定数クラスを分ける
  • 内部クラスで種類ごとにまとめる
  • partialで種類別にファイルを分ける


 

さいごに


本エントリでは、自然に「const」ではなく「static readonly」を使用している。
理由はあるが、長くなりそうなのでまた後日。



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿