HYSOFT

2003.11.3更新

プログラミング談

このページは,私がいろいろ経験してきたことを忘れないように記してきたメモの一部です。思い切って公開しますが,あくまでも私用のメモであるのでわかりにくいところがあります。なお,このページは以下のことを前提に読んでください。考え方というのはその人の経験や立場により大きく異なってくるからです。

良いシステムとは

ユーザの要求を満たすシステムである。具体的には,ユーザの目的が達成でき,バグがなく,使いやすく,正確で,高速で,追加変更が容易なシステムである。そのためには,わかりやすいコードからなるシステムでなければならない。逆に言えば,わかりやすいコードからなるシステムであれば,バージョンアップが容易であるから,バージョンアップを重ねていくことで良いシステムとなる可能性が高い。

開発手法について

システムの種類により,構造化手法,オブジェクト指向手法と使い分けることが大事である。適材適所である。何でもかんでもオブジェクト指向で開発する必要はない。目的はわかりやすいコードからなるシステムであるのだから。

ゼロから作る必要はない。既存のプログラム,過去の事例,パターン等をガンガン使うこと。

デザインパターンについて

デザインパターンとは間接性を入れることにより変更に強い再利用しやすいシステムを作るためのしくみである。間接性が入るからコードの可読性は損なわれる。(何をやっているのかを理解するためにクラスを一つひとつ追っていかなければならないし,そもそもパターンを知らなければ理解できない。) 個人的には少々変更箇所が増えても変更箇所がすぐにわかるような可読性のあるわかりやすいコードであるほうが大切であると思う。したがって,普通の開発者が無理して使う必要は一切ないのである。  しかし,フレームワークやクラスライブラリではこういう複数箇所の変更は致命的なのでデザインパターンを使うしかない。つまり,デザインパターンとは,フレームワーク開発者,クラスライブラリ開発者が使うものである。ただ,フレームワークを利用する開発者は知っておいたほうがよい。フレームワークがなぜこういう仕様になっているのかがわかると開発効率が上がるからである。もちろん,普通の開発者にとってもいくつかのパターンは大変有用である。そして,オブジェクト指向プログラミングの大変良い教材である。学んでおくに越したことはない。

データベースを使うシステム

基本的にはオブジェクト指向でなくデータ中心アプローチで開発するべきである。この場合,データベース化される部分がモデルであり,その他がビューとコントローラになる。もちろんデータベース部分以外はオブジェクト指向で開発してもよい。SQLデータベースを使用するシステムなのに,SQLで素直に操作するのではなく,オブジェクトに変換してごちゃごちゃやっているのを良く見るが,いったい何をやっているのだろうと思う。SQLで書いたほうが絶対に効率的でありアクセススピードも速いしわかりやすい。

オブジェクト指向分析

分析とは現実世界のモデル化であるが,設計段階で結局RUPのバウンダリ,コントロール,エンティティ構造になるのだから最初からこの構造を意識して分析(設計)してよいと考える。現時点では???

オブジェクト指向設計について

依存性(dependency)について

依存性とは自オブジェクトが目的のオブジェクトを一時的に使うということである。関連と違い,自オブジェクトは目的のオブジェクトのポインタをフィールドとして所有していない。 具体的には,以下の3つの場合がある。

  1. メソッドの引数として目的のオブジェクトのポインタを得る場合

    クライアントから目的のオブジェクトのポインタを渡してもらう。逆に言えばクライアントは目的のオブジェクトのアドレスを知っていなければならない。この方法はCでよくやる,構造体のポインタを関数に渡す方法と同じである。この方法は関連と違い,クラス間の依存関係が小さくなるので良い方法であると思う。たたし,使用する側のオブジェクトのメソッドがひとつの場合に限る。複数のメソッドから目的のオブジェクトを使用するのであれば関連を使うべきだろう。 既に存在するオブジェクトにちょっとだけ仕事をしてもらうというときに使う。自オブジェクトのアドレスを目的のオブジェクトに登録するための方法としてデザインパターンなどでは良く使われている。

  2. メソッドの中でnewして使う場合

    この方法は対象がヘルパーオブジェクトの場合はちょくちょく用いられるであろうが,問題領域のオブジェクトの場合はあまりないだろう。なぜならこの方法は,まだ存在しないオブジェクトにちょっとだけ仕事をしてもらう場合となるが,これこそヘルパーオブジェクトであるからである。Cでの関数を使うことと同じイメージであろうか。ただ,コントローラなどの上位部分では使うかもしれない。(浅海p107では使用している。)

  3. 親オブジェクトから目的のオブジェクトへのポインタを取得する場合

    親オブジェクトへのポインタはフィールドとして所有しているのがふつうである。そしてメソッドの中で目的のオブジェクトへのポインタ変数を宣言し,親オブジェクトから目的のオブジェクトへのポインタを取得し代入して利用する。( Son son = parent.GetSon(); )この方法はデメテルの法則に違反するがちょくちょく用いる手法である。この方法は依存性に分類されるが,関連の関係とほとんど変わらないと考えていいと思う。ただし,個人的にはデメテルの法則に従いたいのでできるだけ使いたくない。

関連(association)について

オブジェクトが協調動作するためには関連が必要である。しかし例えばネットワーク状の関連になるとコードがわかりにくくなると私は考える。だからできるだけ木構造的(中央集権的)な関連になるよう心がけたい。分析段階ではネットワーク状になることは避けられないと思うが,設計段階で木構造的になるように変更する。ただし,この考え方はまだ確信レベルまでにはいたっていない。なぜなら中央集権的というのはオブジェクト指向的でないかもしれないからである。ただ,オブジェクト指向的であるかどうかよりも,わかりやすいコードが書ければそれでよいとも思うのだが。

C++でのプログラミング方針

オブジェクトはコピーしない。

「方針」

オブジェクトはコピーしない。ポインタで渡す。もちろんコピーコンストラクタが起動されないように,他のオブジェクトによる初期化もしない。

「理由」

operator=の多重定義や,自作のコピーコンストラクタを書きたくないからである。ただ,そもそもオブジェクトのコピーは現実的にはおかしなことであり,こういう機会はめったにない。(stringなどのヘルパーオブジェクトは別)

「メリット」

operator=を多重定義する必要がない。自作のコピーコンストラクタを書く必要がない。

多重継承は使わない。

「方針」,「理由」

多重継承を効果的に使うのは難しい。幸い多重継承がぜひ必要だということは実際ほとんどない。もし必要としても代替案として,オブジェクトコンポジション,javaのinterface的(状態を持っていない抽象基底クラスということ)な使い方がある。つまり多重継承は不要である。

「メリット」

多重継承のごたごたを考えないですむ。

constのことはあまり気にしない。

「方針」,「理由」

constのことを気にするとプログラムがすらすらかけない。また,コードは読みにくくなる。つまりconstの意義は理解しているが,面倒なのである。constがあろうとなかろうとプログラムの構造には影響がない(cargill)。

「メリット」

プログラムがすらすら書ける。読める。

演算子の多重定義はしない。

「方針」,「理由」

演算子の多重定義は誤りを犯しやすく,落とし穴に十分注意しなければならず,書くのが難しい。幸い数学的な計算以外では必要になることはほとんどない。また素直にメンバ関数を書けばよいのである。無理して使うことはない。どうしても必要なときは,effective c++を片手に十分注意して使うこと。

「メリット」

C++の複雑な一面から開放される。

Tips