第25回 クラスの設計
この連載を読んでいただき、ありがとうございます。
「大発見やー」と自画自賛していることを書いてみたいと思いますが、もしかしたらそんなのは当たり前のことなのかもしれません。プロのプログラマーは隠してるんじゃないの?みたいに思えてきますが。
まず、私の設計方針である「iOSとAndroidで同じクラス設計をする」というところから振り返りますが、図式化すると次のようになります。
最初のクラスはアプリの管理クラスですね。
続いて呼ばれるのが、画面の管理クラス。
実装はいろいろあると思いますし、ここでstoryboard,XMLファイルが登場するのが教科書では多いですよね。
で、私の場合は、この画面を提供するクラスから、画面表示パーツを呼び出しています。
一つのビューを作ってそれを表示するだけの教科書的な説明では、この形でも十分だとは思うのですが。本屋さんにある解説書はほとんどそうですよね。
今まで、これが自然な流れだと思っていたし、なんの疑いも持たなかったのですが、このままだと次のようなことが起こってきます。
Teamクラスを作って、それをEntryViewを作るとき渡す。終われば返してもらう。
Runningクラスを作るとき、渡す。終われば返してもらう。
渡したとき、Teamクラスの中身をいじるのが普通ですよね?
エントリーされたら、フラグを立てたり、新規のメンバーを追加したり、ラップデータを記録したり。
Teamクラスが移動していくのはとても不合理です。だいたい、うまく返るのかどうかも怪しいです。
Teamクラスが動くのがいけないんだと考えたとき、閃いたのが、「Team クラスを中心にしよう。」だったわけです。コペルニクス的転回ですよね。かつて、天動説に取って代わって地動説が合理的と判断されたのと同じです。
さて、クラス設計は次のように変わりました。
あるメニュー表示するとき、Teamクラスに「このメニューを表示するよ」と伝わります。すると、Teamクラスは、下位のビューを作るクラスに指示を出し、必要な名前を渡して、ビューを返してもらいます。それを画面を表示するクラスに返して、表示するという寸法です。
このような実装に変わっています。(java版)
呼び出し側(抜粋)
public void showEntryMenu() { // 以前のビューは消しておく this.removeAllViews(); // 端末のサイズを取得 final int width = this.getWidth(); final int height = this.getHeight(); // Entry のインスタンスを作成。 EntryView entryView = myTeam.entryMenuView(width,height); entryView.setBackToMenu(new Runnable() { @Override public void run() { showMainMenu(); } }); // Androidではレイアウトパラメーターを使用 LayoutParams mainMenuParams = new LayoutParams( width,height ); mainMenuParams.addRule(CENTER_IN_PARENT); mainMenuParams.addRule(CENTER_IN_PARENT); // ビューを画面中央に表示 addView(entryView, mainMenuParams); }
10行目のところがTeam.entryMenuView(width,height); という形に変わっています。Teamクラスに作るように指示を出しているわけです。
Teamクラス(抜粋)
public EntryView entryMenuView(int width, int height) { ScrollView scrollView = new ScrollView(myContext); RunnerList listView = new RunnerList(myContext,width*8/10,width*13/100); // 選手名と番号を入れるメソッド for (int i=0; i<runners.size(); i++) { listView.setRunnerView(i+1,runners.get(i).getName()); } scrollView.addView(listView); return new EntryView(myContext, width,height,scrollView); }
Teamクラスでは
RunnerListを作った後、氏名を送って、氏名入りのビューを完成させます。
これで、TeamオブジェクトやRunnerオブジェクトをコピーしたりするややこしいことはしなくて良くなって、一安心。
管理すべきデータを中心に考えるというのは多分当たり前?
それなら、今までやってたのはなんだったんだろう?