2012年3月16日金曜日

シングルコンテキストでの設計方法(3)

Titanium Mobileを使ったアプリ開発において、シングルコンテキストで作る際の工夫の続き、第3回です。3つのレベルに分けてJavaScriptを作る、という話でした。今回は、その中のレベル1の作り方について、少し詳しく書きます。

 

レベル1のJavaScriptに入れるのは、適用業務に無関係なプログラム上の機能です。代表的なものとして、共通のアラート、確認を求めるダイアログ、タイマー処理、簡単なアニメーションなどです。アニメーションというのは、ウィンドウのオープンやクローズの際のアニメーションだけではありません。文字入力するときにソフトキーボードが出て、画面の下側にある入力フィールドが見えなくなる問題への対応です。TextFieldなどをViewの上に置き、Viewごと上に移動する機能を実現します。

こういった機能も必要ですが、もっとも大事なのは、UI部品の記述を簡単にすることです。Titanium Mobileで作り始めて面倒に感じるのが、Ti.UI.createXXXとして記述するUI部品の生成処理でしょう。行数が増えるだけでなく、数多くのUI部品を付けるほど、ソースコードが長くなってしまいます。レベル1のJavaScriptとなる「base.js」に、UI部品を生成する関数を用意します。

// base.js (レベル1)
bb = {};
(function() {
    bb.createWinF = function(_title){
        return Ti.UI.createWindow({
            title:_title,
            backgroundColor:'#fff'
        });
    }
    bb.createLblF = function(_text, _fontSize, _textAlign, _height, _width, _top, _left){
        return Ti.UI.createLabel({
            text:_text,
            font:{fontSize:_fontSize},
            textAlign:_textAlign,
            height:_height,
            width:_width,
            top:_top,
            left:_left 
        });
     }
    bb.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
        });
    }
})();

レベル1の関数なので、用意したグローバル・オブジェクトの「bb」に、直接加えています。これらは、外から呼ぶことが可能なようにと「bb」に加えているわけです。逆に、base.js内でしか呼ばれない関数は、普通に「function func_name() { ... }」の形で書いて構いません。

こうした用意した関数をレベル3のJavaScriptで利用すると、次のような感じになります。

// pe_prod_edit.js (レベル3)
(function() {
    bb.pe = {};
    bb.pe.win = bb.createWinF('prod_edit');
    var lblTitle = bb.createLblF('商品情報編集', 36, 'center', 70, 'auto', 20, null);
    bb.pe.win.add(lblTitle);
    var lblMsg = bb.createLblF(' ', 18, 'left', 30, 500, 700, 200);
    bb.pe.win.add(lblMsg);
    var btnSave = bb.createBtnF('保存', 24, 40, 200, 100, 32);
    btnSave.addEventListener('click', saveDataF);
    bb.pe.win.add(btnSave);

    function saveDataF() { ... }
})();

普通に記述する方法よりも、格段に短くなったと感じたのではないでしょうか。UI部品の数が多くなるほど、その効果の大きさに感激します。無駄な記述が格段に減り、アプリ全体でのソースコードの量も大きく減ります。また、生成する処理の行が長くならないので、別に分ける必要もなく、生成内容と処理を近くに書けます。

これでもまだ不満、addすら何度も書きたくないという人には、生成する関数にaddも含めてしまう方法があります。

// base.js (レベル1) addを追加したもの
bb = {};
(function() {

    bb.createLblF = function(_view, _text, _fontSize, _textAlign, _height, _width, _top, _left){
        var lbl = Ti.UI.createLabel({
            text:_text,
            font:{fontSize:_fontSize},
            textAlign:_textAlign,
            height:_height,
            width:_width,
            top:_top,
            left:_left 
        });
        _view.add(lbl); // addします
        return lbl;
     }
    bb.createBtnF = function(_view, _title, _fontSize, _height, _width, _top, _left){
        var btn = Ti.UI.createButton({
            title:_title,
            font:{fontSize:_fontSize},
            height:_height,
            width:_width,
            top:_top,
            left:_left
        });
        _view.add(btn); // addします
        return btn;
    }
})();

これを利用する側のJavaScriptは、前よりもさらに短くなります。

// pe_prod_edit.js (レベル3) add対応版
(function() {
    bb.pe = {};
    bb.pe.win = bb.createWinF('prod_edit');
    var lblTitle = bb.createLblF(bb.pe.win, '商品情報編集', 36, 'center', 70, 'auto', 20, null);
    var lblMsg = bb.createLblF(bb.pe.win, ' ', 18, 'left', 30, 500, 700, 200);
    var btnSave = bb.createBtnF(bb.pe.win, '保存', 24, 40, 200, 100, 32);
    btnSave.addEventListener('click', saveDataF);

    function saveDataF() { ... }
})();
UI部品の標準設定のまま使う限り、addまで含めて1行で済んでしまいます。たいへん見やすいソースコードになりますね。私が作った業務アプリは、addを含まない生成関数を使いました。次に作るものは、addを含んだ生成関数を使おうと思っています。

addを含めた作り方は良いけど、addしない使い方も可能にしたいというワガママな要望がある場合は、次のように条件式を入れます。

// base.js (レベル1) addワガママ版
bb = {};
(function() {

    bb.createBtnF = function(_view, _title, _fontSize, _height, _width, _top, _left){
        var btn = Ti.UI.createButton({
            title:_title,
            font:{fontSize:_fontSize},
            height:_height,
            width:_width,
            top:_top,
            left:_left
        });
        if (_view) _view.add(btw); // 条件付きadd
        return btn;
    }
})();
// pe_prod_edit.js (レベル3) addワガママ版を利用
(function() {
    bb.pe = {};

    // 普通にaddするボタン生成
    var btn1 = bb.createBtnF(bb.pe.win, '保存', 24, 40, 200, 100, 32);
    // addしないボタン生成
    var btn2 = bb.createBtnF(null, '隠れ保存', 24, 40, 200, 100, 32);

})();

こんな感じで、いろいろとアレンジできますね。addしない生成にどんな使い道があるかは別にして。また、どんなアレンジを加えるかは、最終的に好みの問題でしょう。

 

生成関数を作る際の考慮点も、いくつか紹介します。生成関数で作るUI部品の設定は、アプリ内で一番標準的な形を選びます。そして、標準以外の設定で使いたいUI部品は、生成関数で作った直後に、好みの形に設定を変更します。こうすることで、アプリ全体の記述がもっとも少なくなるはずです。また、標準設定を変更するコードが加わることで、標準設定から何を変えたのか、すぐ理解できるようになります。このような関数を使わず、すべての設定が並んでいる記述だと、どの設定が他と違っているのか、非常に見付けにくいですから。

// pe_prod_edit.js (レベル3) 標準設定を変更する
(function() {

    var lblMsg = bb.createLblF(bb.pe.win, ' ', 18, 'left', 30, 500, 700, 200);
    lblMsg.color = '#888'; // 標準設定を変更

    var btnSave = bb.createBtnF(bb.pe.win, '保存', 24, 40, 200, 100, 32);
    btnSave.addEventListener('click', saveDataF); // これも変更の一つ

})();

アプリによっては、2種類の設定を多用することもあるでしょう。そんなときは、生成関数を1つに制限せず、2種類の設定を持った別々の生成関数を用意して使い分けます。2種類の設定を別々に持てるので、設定の変更もそれぞれ一箇所で済みます。もちろん、生成関数が1つの場合も、標準設定の変更が一箇所で済みますね。

 

引数の並び順も、できるだけ標準化したい点です。add版で考えると、add対象のビュー、ボタンなどの名前を最初に入れるでしょう。それ以降も、できる限り同じ値を入れて、先頭からの並び順を統一したくなります。候補としては、縦横の大きさと位置の4つの値が一番の候補でしょう。

しかし実際に試してみると、この4つの値は、もっとも右側に並べるのがベストです。UI部品を生成した行は、他の行よりも長くなります。すると、生成行の右側の値だけが、何もない空間に存在するような感じに見えるのです。その場所に4つの値を置くと、4つの値が見付けやすくなります。この4つの値は、UI部品の大きさと位置を調整するために何度も変更することが多く、少しでも見やすい形で作っておきたいのです。

というわけで、引数のお薦め並び順は、add対象のビュー、ボタンなどの名前、その他の設定値、縦横の大きさと位置の4値となります。最後の4つの値の並び順を統一することは、言うまでもありませんね。

Titaniumu Studioを使っていると、関数の引数を表示してくれるので、引数の並び順を覚えておく必要はありません。実際には、ラベルやボタンを生成した行をコピー&ペーストして、必要な箇所だけ引数を変更することが多いので、Studioの引数表示すら、めったに使いませんけどね。

 

以上のような形でレベル1のJavaScriptに、ウィンドウ、ビュー、タブビュー、ラベル、ボタン、テキストエリアなど、通常なら10種類ほどの生成関数を用意します。Ti.UI.createXXXとして作るものは、基本的にすべて対象となります。あとは、レベル3のJavaScriptでガンガン使うだけです。レベル3の記述が簡素化され、見やすいプログラムになるでしょう。

メリットを整理すると、次のようになります。

・UI部品を生成する長い記述がたった1箇所で済む(アプリ全体での記述量も減る)
・個々のUI部品生成は1行で済み、簡潔で読みやすくなる
・生成処理を別に分ける必要もなくなり、生成設定と処理を近くに置ける
・UI部品の大きさや表示位置の数値が右側に飛び出した感じで、変更するときに見付けやすい
・UI部品の標準設定を変更するとき、一箇所だけ直せばよい
・標準設定のまま使わないUI部品が、何を変えたのか見分けやすい

今回は、短いとはいえソースコードをいくつも貼り付けたので、全体が長くなってしまいました。レベル2とレベル3の作り方は、別な投稿に分けます。

0 件のコメント:

コメントを投稿