前回の隠蔽化の話を受け、実際のプログラムの例を課題に説明。 複素数クラスを(実部,虚部)で実装した後に、(絶対値,偏角)に直したら…
基本プログラム(実部と虚部)
複素数を扱うクラスを作るのであれば、基本的には以下の様なコードとなるだろう。 複素数どうしの簡単な加算・乗算を記載する。
class Complex { private: double re , im ; public: Complex( double x , double y ) { re = x ; im = y ; } // 上記コンストラクタは、以下のようにも書ける。 // Complex( double x , double y ) // : re( x ) , im( y ) // { メンバ以外の初期化... } void print() { printf( "%lf+j%lf¥n" , re , im ) ; } void add( Complex &z ) { re = re + z.re ; im = im + z.im ; } void mul( Complex &z ) { double x = re * z.re - im * z.im ; double y = re * z.im + im * z.re ; re = x ; im = y ; } } ; int main() { Complex a( 1 , 2 ) ; Complex b( 2 , 3 ) ; a.add( b ) ; a.print() ; a.mul( b ) ; a.print() ; return 0 ; }
Complexクラス内部をリファクタリング
しかし、前述プログラムでは、mul()メソッドは、add()メソッドよりは、 複雑なものとなっている。 しかし、複素数の乗算は、(絶対値と偏角)を用いれば、絶対値の乗算・偏角の加算で 処理は簡単に記述できる。そこで、クラス内部を乗算と偏角で処理をするように変更してみる。
class Complex { private: double r , th ; public: Complex( double x , double y ) { r = sqrt( x*x + y*y ) ; th = atan2( y , x ) ; // atan2は象限を考慮してくれる } void print() { printf( "%lf ∠ %lf¥n" , r , th / 3.141592 * 180.0 ) ; } void add( Complex &z ) { // ここは面倒な式になっちゃう } void mul( Complex &z ) { r = r * z.r ; th = th + z.th ; } } ; int main() { Complex a( 1 , 2 ) ; Complex b( 2 , 3 ) ; a.add( b ) ; a.print() ; a.mul( b ) ; a.print() ; return 0 ; }
ここで重要なポイントは、2つめの絶対値∠偏角のプログラムの呼び出し側 main() は、 1つめのプログラムとまるっきり同じである。
このように、オブジェクト指向の隠蔽化を行っていれば、当初のクラス設計が悪くて後で変更 したくなった場合、利用者側からの見た目の動作を変更せずに、内部のデータ構造や処理メソッドを 変更が可能となる。 このように、利用者側からの見た目を変更せずに処理の内部を変更すること、 リファクタリング と呼ぶ。これにより、プログラムの不備や問題点があっても、積極的にプログラムを 改良できることから、不備の少ない安全なプログラムを作れるようになる。
隠蔽化の課題
以上の2つのプログラムで複素数の計算メソッド、加算(add),除算(sub),乗算(mul),除算(div)…その他を (実部,虚部)、(絶対値,偏角)で記載し、適切に記述をすれば、呼び出し側main()を まるっきり同じものにできることを通して、隠蔽化についてレポートにまとめよ。
レポートでは、以下の点を記載すること。(レポートは、本科中間試験の頃までに提出が望ましい)
- 2つの方式でのプログラム例
- 上記プログラムに対する説明
- 上記プログラムが正しく動作していたことが判る結果
- この課題から判る考察