2012年4月26日木曜日

間接参照は利用側の目的指向で作成する

じっくりとテストする時間が取れないので、今日は少し、ソフトウェアを作るときのコツというか考え方について少し書きましょう。取り上げるのは、基本中の基本といえる間接参照です。

 

ソフトウェアの中で、幅広く利用されている作り方に間接参照があります。データ自体を直接参照する代わりに、間に1つ以上の参照を挿入し、何段階かの参照を組み合わせる方法です。ハードウェアに近い部分からアプリケーションまで、幅広く使われています。

たとえば、OSのメモリー管理を間接参照にすることで、使っているメモリー部分を集めるために、メモリー上のデータをOSが移動しても、アプリでは問題なくメモリー上のデータが使えるのは、間接参照のおかげです。オブジェクト指向の仕組みも、間接参照の凝った使い方です。ソフトウェアの柔軟性を増すための基礎的な仕組みが間接参照なのです。

もちろん、欠点もあります。参照回数が増えることで、そのための処理が必要となり、処理速度は低下します。しかし、CPUパワーが向上した現在では、あまり気にならなくなりました。それ以上に、ソフトウェア変更での柔軟性を増す価値のほうが格段に大きくなっています。

 

このブログの最初のほうで、UI部品を生成するための関数を紹介しました。最終版は次のようなコードでした。

// ボタンの生成(base.js)
exports.createBtnF = function(_title, _fontSize, _height, _width, _top, _left){
    return Ti.UI.createButton({
        title:_title,
        font:{fontSize:_fontSize},
        height:_height,
        width:_width,
        top:_top,
        left:_left
    });
}
// 上記の関数を利用する(main.js)
bbb = require("base"); // レベル1を使えるようにする
(function() {
    bb.win = bbb.createWinF('prod_edit');
    var btnOpenPe = bbb.createBtnF(bb.win, '商品編集', 24, 40, 200, 100, 32);
    btnOpenPe.addEventListener('click', openPeWinF);
    ...
})();

これも間接参照です。UI部品の生成コードを直接書く代わりに、生成関数を呼び出す形にします。メリットとしては、生成する部分のコードが1行で済むことです。加えて、生成するボタンのデフォルト設定を自由に変えられます。また、デフォルトを変更して使うボタンでは、生成直後に変更する部分(主にプロパティ)の変更コードを追加するので、どこを変えたのか一目瞭然となります。間接参照ならではのメリットです。

このような使い方を、間接参照の利用方法として捉えると、設定の挿入と見ることができます。参照を間に1つ挿入しながら、挿入した部分でデフォルト設定を持てるようにしてるわけです。デフォルト設定を持つことで、デフォルト設定を変更するときの柔軟性を確保するとともに、利用する側での記述も減らしています。

 

他の例では、プログラム内で使う定数宣言も間接参照です。C言語の時代から普通に行なわれていました。JavaScriptにも同様の構文があり、constを付けて宣言します。JavaScriptに限りませんが、定数宣言の作り方には少し注意点があります。例で説明したほうが分かりやすいでしょうね。アプリで表示するメッセージの色を定義する場合を考えてみましょう。エラーなら赤、注意なら青、処理が成功した報告では緑、その他は黒と決めました。そのまま、次のように作ることも可能です。

// メッセージの色を定数宣言(色で名前を付ける)
const COLOR_RED = '#f00';    //色:赤
const COLOR_BLUE = '#00f';   //色:青
const COLOR_GREEN = '#0a0';  //色:緑
const COLOR_BLACK = '#000';  //色:黒

このように作れば、色を細かく変える場合に変更は一箇所で済みます。しかし、処理成功を青、注意をオレンジに変更したくなったらどうでしょう。もちろんCOLOR_GREENを青色の00fに変更すれば可能ですが、GREENと定義してあるのに色が青では混乱の原因になります。それを避けようとして、COLOR_GREENと記述してある箇所を、すべてCOLOR_BLUEに置き換えることになるでしょう。

同じ内容を、もっと違った視点で作ると、より変更に強い作り方になります。色の名前で定義するのではなく、各色の利用目的の名前で定義するのです。具体的には、次のように作ります。

// メッセージの色を定数宣言(色の利用目的で名前を付ける)
const COLOR_ERROR = '#f00';  //色:赤
const COLOR_ALERT = '#00f';  //色:青
const COLOR_OK = '#0a0';     //色:緑
const COLOR_STD = '#000';    //色:黒

色の利用目的で名前を作り、何色なのかはコメントで示しています。このような形だと、宣言した名前が「エラーの色」となっているため、エラーの色は何色でも大丈夫になります。エラーの色は、エラー表示の箇所でしか使いませんから、余計な置き換えも生じません。色の変更も、色の値とコメントだけで済みます。毎回、たった1行の変更で済むでしょう。

 

実は、上の例こそ、間接参照を上手に使う鍵なのです。間接参照を作るときに間に入れるもの(上の例ではconstによる定数宣言)は、それを「使う側の利用目的ごとに別々に用意する」のが基本なのです。逆に、色の名前で作ったものは、利用目的ではなく、値そのものの名前で作ったと捉えることができます。値そのもので名前作ったわけですから、値の変更に名前が影響されます。その名前は参照に使う名前なので、利用する側の変更も生じさせ、変更への柔軟性が低下するわけです。間接参照を名前で参照する以上、「参照で使う名前を変えなくて済むように作る」というのが大事なのです。

「別々に用意する」の意味が分かりやすいように、同じ色定義の例を利用しながら、もう少し別な状況を考えてみましょう。メッセージの色に加えて、枠線の色も何種類か使う状況だとします。この場合も、色の名前で定数宣言すると、前にも増して大変なことになります。メッセージの赤と枠線の赤が一緒に宣言してありますから、片方だけ変えたいときに、色の値を変更すると、もう片方の色も一緒に変わってしまいます。両者を区別するためには、二つの宣言に途中で分けなければなりません。具体的な作業としては、COLOR_REDを使っている箇所を全部調べて、片方を別の名前に変更する必要があります。考えただけでも大変そうです。直し忘れが生じていて、公開してから気付いたなんて状況も起こりそうで怖いです。

では、どのように作るべきなのでしょうか。鍵は「使う側の利用目的ごとに別々に用意する」ですから、メッセージの色と枠線の色では利用目的が異なります。たとえ同じ色であっても、別々に定義するのが基本です。次のような形になるでしょう。

// メッセージの色を定数宣言
const COLOR_MSG_ERROR = '#f00';  //色:赤
const COLOR_MSG_ALERT = '#00f';  //色:青
const COLOR_MSG_OK = '#0a0';     //色:緑
const COLOR_MSG_STD = '#000';    //色:黒
// 枠線の色を定数宣言
const COLOR_BORDER_EDIT = '#f00';   //色:赤
const COLOR_BORDER_BROWSE = '#00f'; //色:青
const COLOR_BORDER_CHECK = '#0a0';  //色:緑
const COLOR_BORDER_ETC = '#000';    //色:黒

色の定数宣言だと示す言葉COLORに続いて、利用目的の分類または対象となる言葉のMSGかBORDERを付けます。最後に、分類または対象ごとの、具体的な目的を示す言葉を加えれば完成です。今回の例では、最初の定数宣言をMSG入りに変更しました。同じことが、開発の途中で起こりえます。そうなると利用する側の変更が生じるでしょう。ですから、メッセージの色しか作らない場合でも、最初からMSGを入れて定数宣言するのが、より良い作り方といえます。

上記の定数宣言は、まったく同じ色を宣言していますが、利用する目的が異なるから別々に作ったわけです。定数宣言の重複だと考える必要はありません。この作り方のほうが、変更への柔軟性は格段に上です。

 

ここまででも、予想外に長くなってしまいました。続きは、気が向いたらというか、別な機会に書くということで。

0 件のコメント:

コメントを投稿