先週までの3回で拵えた
「ColorRGB」「ColorCMY」「ColorHSB」
のプログラムを思い出してみてください。そのいずれも、幾つかの色素を持ち合わせていたり、数値を正規化したり、背景色を更新したり...と、プログラムの構造に重複が見られたと思います。
これからまた新しい「ColorXXX」を作るとすれば、また同じような構造を同じように作らねばなりません。そろそろ嫌気が差してきませんか?
そこで今回は、あらゆる「ColorXXX」の土台となる抽象クラス「ColorAbstract」の作成に取り組みます。
先週までは同じ事の繰り返しで眠気も生じたと思いますが、今回はその気色が一変します。
プログラムの知識のみで単純な括り出しを行うのではなく、色の合成に関する知識を引用してプログラムの構造を適切に切らねばなりません。
言うは容易し「抽象化」の難しさや奥深さとともに、オブジェクト指向の何たるかを垣間見ることができれば良いのですが...。
ちなみにテキストはこちら(http://www.cc.kyoto-su.ac.jp/~atsushi/Programs/ColorAbstract/index-j.html)
マシンメンテナンス
メンテナンス事項は記憶に定着してきたでしょうか。(日々のマシンメンテナンス)
準備プログラムの実行
以下を実行すれば、リファクタリングの準備が整います。
| aCollection |
(aCollection := OrderedCollection new)
add: #url: -> 'http://www.cc.kyoto-su.ac.jp/~atsushi/Programs/ColorAbstract/ColorAbstract.st';
add: #comment: -> 'Copyright 2008-2011 KSU (Kyoto Sangyo University). All Right Reserved.';
add: #bundle: -> #KSU;
add: #package: -> 'KSU-Template';
add: #nameSpace: -> #KSU;
add: #category: -> 'KSU-Template';
add: #class: -> #{KSU.ColorAbstract};
add: #protocol: -> #'interface specs';
add: #selector: -> #windowSpec;
add: #execute: -> [];
yourself.
JunSystem
perform: ((aCollection collect: [:each | each key]) inject: String new
into: [:selector :key | selector , key]) asSymbol
withArguments: (aCollection collect: [:each | each value]) asArray
動作確認
ColorRGB、ColorCMY、ColorHSBが共に独立して動く様子を確認しておきましょう。リファクタリングの後も、変わるところなく同じように動作しなければなりません。
動作確認を済ませたら、それぞれのアプリケーションについてザックリと振り返っておきましょう。
復習:ColorRGB
フィールド用とスライダー用とで2種類のValueHolderを持っていました。(redFieldやらredGaugeやら。)また、valueString:では浮動小数点数の丸めも行いました。
復習:ColorCMY
2種類のビュー(スピンボタンとプログレスバー)から、1つのモデルを参照していたのでした。
復習:ColorHSB
独自のGUI部品(ColorHSBView、ColorHSBController)が用意されていました。
まずは落としてきたプログラムの構造を把握し、これから目指すべき構造を明確にしましょう。あとは目標に向かって思索を繰り返すのみ。
現状の把握
今回の課題(要求)は「リファクタリング」です。その解決のために、まずは現状把握を行いましょう。さあ、缶詰(クラス名のみの表記)で構いませんので現状のクラス図を描いてみてください。
登場人物は誰でしょう。どのような繋がりがあるでしょう。
現状の瓶詰め(フィールドやメソッドも表記)も併載しておきますので、参考までに。
目標の設定
では次に、目標となる構造(基本設計)を描きましょう。これも缶詰で問題ありません。
以前は、Color{RGB,CMY,HSB}ともにApplicationModelを継承していましたが、抽象クラス「ColorAbstract」を挿むような構造に変更します。
紙の上で抽象化
目標の構造が見えましたので、その目標を更に具体的なもの(詳細設計)に落とし込みましょう。
プログラミングの知識だけでなく色合成の知識も援用し、適切な切り・貼り・盛り・削り(リファクタリング)を行います。
リファクタリングの計画(Plan)が終われば、次は実行(Do)に移しましょう。
先の節では「紙の上で抽象化」を行いましたが、それをプログラムに落としこんでゆきます。コードリーディングとコードライティングを同時並行で行います。
コードリーディング:ColorAbstract
すでに用意されている抽象クラス「ColorAbstract」の理解から始めましょう。
抽象クラス特有の「self subclassResponsibility」や、メソッド名・変数名の抽象度に注目してください。
ColorCMYのリファクタリング
先に拵えた計画に従って、ColorCMYにリファクタリングを施してゆきましょう。3つのクラスの中では、最もリファクタリングの容易なクラスになります。
- ColorAbstractを継承する(Definitionタブ)
- インスタンス変数(cyanGauge、magentaGauge、yellowGauge)を削除する(Definitionタブ)
- initialize、postOpenWith:、updateColor、updateColor{Cyan,Magenta,Yellow}、menuBarの削除
- cyanGauge、magentaGauge、yellowGaugeの修正
ColorHSBのリファクタリング
次にColorHSBのリファクタリングを行いましょう。ColorHSBViewやColorHSBControllerについては、今回はそっとしておいて、簡単なリファクタリングのみを施します。
- ColorAbstractを継承する(Definitionタブ)
- インスタンス変数(hueGauge、saturationGauge、brightnessGauge)を削除する(Definitionタブ)
- initialize、postOpenWith:、updateColor、updateColor{Hue,Saturation,Brightness}、menuBarの削除
- hueGauge、saturationGauge、brightnessGaugeの修正
ColorRGBのリファクタリング
- ColorAbstractを継承する(Definitionタブ)
- インスタンス変数(redGauge、greenGauge、blueGauge)を削除する(Definitionタブ)
- postOpenWith:、updateColor{Red,Green,Blue}、menuBarの削除
- initialize、redGauge、greenGauge、blueGaugeの修正
- updateColorの修正
はてさて、updateColorの修正は上手くできたでしょうか。その実装例として如何に画像を示しておきます。
中でも注目すべきは、オブジェクトに送信するメッセージを動的に生成していること。perform:メッセージの扱いについて少し練習してみましょう。
perform:メッセージ
以下に示す例は、どれもValueHolderの値を得るための操作であり、同じことを意味します。
同様に引数を伴うメッセージも、多様な表現方法があるのです。
リファクタリング後の動作確認
リファクタリングの実行(Do)が終われば、次は検証(Check)を行いましょう。リファクタリング前と同じように正しく動作しますか?
もし問題があれば、変更部分をもう一度よく確認し、しっかりと改善(Act)を行いましょう。
今日の内容には「計画(Plan)」「実行(Do)」「検証(Check)」「改善(Act)」という言葉を含めておきました。
すでに聞き及んでいると思いますが、これら4点の反復を「PDCAサイクル」と呼び表します。
企業活動・事業活動の根幹的構造とも言えるこのサイクルは、今日垣間見た通りリファクタリングにも言えることなのです。
つまり、リファクタリング(ソフトウェアの変化)は何度となく繰り返すものであり、今日のリファクタリングもその1サイクルに過ぎません。
そしてこのサイクル(リファクタリング)の継続は、まさに「エクストリームプログラミング(XP)」に相当します。
今はまだ、わからなくとも焦る必要はありません。これから数ヶ月を掛けてゆっくりじっくりと染み込ませることになります。
その仕込みを終えて解題を受けた時、少し大袈裟な言い方ですが、きっと全てが繋がるはずです。今はその肥やし(いずれ繋がる要素)を蓄えることに尽力してください。
終始、偉そうな言い方ばかりで不快に感じたかもしれませんが、どうか許してください。
また、データの保存もお忘れなく。