- - PR -
C#(オブジェクト指向)での検索画面の実装方法
1
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2008-09-10 11:28
お世話になっております。
C#で検索画面を作成しようと思っていますが、オブジェクト指向による実装方法について悩んでいます。 良い方法がありましたら、ぜひご教示頂けないでしょうか。 例えば、条件を指定して顧客データを検索する画面を作るとします。 以下のようなKokyakuクラスが実装済みであると仮定します。 public class Kokyaku { //顧客Noプロパティ public int No { ・・・ } //氏名プロパティ public string Name { ・・・ } //住所プロパティ public string Address { ・・・ } } 検索画面では、顧客No、氏名、住所の「いずれか(複数可)」を条件にして検索するという仕様だったとすると、一般的(雑誌や書籍)には以下のような実装方法が多いと思うのですが、 @検索画面のWindowsフォームにハードコーティング(SQL文を動的生成)する。 public class FormMain : Form { private DataTable searchKokyaku(string sqlWhere) { if(TextBoxKokyakuNo.Text != "") { 入力内容に応じて、SQL文を動的生成する } ・・・ } } A顧客サービスクラスを別に用意して、それをWindowsフォームから呼び出す。 public class KokyakuService { public DataTable Search(int kokyakuNo, ・・・) { if(kokyakuNo != -1) //-1なら条件なしと判断する { 引数に応じて、SQL文を動的生成する } } } 設計やメンテを考えてできる限り、ビュー、モデル、データアクセスは分離したいと考えています。 @では明らかにこれらが混在しており、大きなシステムであったり、機能変更が次々に入れば大変な労力がかかります。 Aは、余計なクラスが多くなり、かなり煩雑なクラス図になると思います。さらに、大抵DataTableインスタンスを返したりして、結局はビューとデータ層が混在する傾向にあると思います。 条件指定が「いずれか(複数可)」だと、条件が未入力かをif文で判断してSQL文を生成するか、いろんな引数のメソッドをオーバーロードする(かなりのメソッド数になる)必要があると思います。 新しいLINQを使えばうまく解決できるのかもしれませんが、良い方法はありますでしょうか。 | ||||||||||||
|
投稿日時: 2008-09-10 11:55
まず、アプリケーションは、ビジネスロジックの分離という観点から、画面がなくても動けるように作っておくほうがなにかと良いです。したがって(1)のようなハードコーディングは避けるべきです。 つぎに、「余計なクラス」というのが本当に余計なクラスならとうぜんなくしたほうが良いですが、存在させる意義があるならばクラスを作ることに躊躇する必要はないでしょう。クラス図にたくさんのクラスが登場してもやむをえないと思います。これは、クラス図を1枚の紙に詰めて書くのが難しいというだけの問題です。
(私は LINQ はぜんぜん知りませんが。) 「条件が未入力か」という情報を、「Kokyakuクラス」に持つほうが良いと思います。(あるいは、「Kokyakuクラス」を集約したラッパークラスにフラグを持つなどでも良いかもしれませんが。) SQL 文の生成は、この「Kokyakuクラス」を入力としておこなうことになります。 | ||||||||||||
|
投稿日時: 2008-09-10 12:12
Kokyakuクラスというのはおそらく、検索結果の1件を格納するためのクラスだと思いますので、それを検索条件としても使うのはあまり賛成できません。
私だったら、検索条件を格納するためのクラスを別途用意し、それを入力にすると思います。顧客IDで範囲検索をおこないたい場合など、Kokyakuクラスでは対応しきれないと思いますし。 ちなみに条件が指定されなかった項目には、 null を入れておきます。
| ||||||||||||
|
投稿日時: 2008-09-10 12:36
ある意味一番重要な、MCV (Model-View-Controller) の C が抜けてます。 .NET の場合、特に MVC の亜種である MVP (Model-View-Presenter) を習得すると良いです。 ちなみに、データアクセスは M・V・P のいずれにも属しません。
レイヤー分けをして、クラス毎のアクセス修飾子を適切に設定 (無駄に public にしない) してやれば、 あとはクラス図の書き方次第で見やすくなるでしょう。
複雑な検索条件を表現したい場合、検索条件をクラス化すると良いかと思います。 ただし、過度な作りこみは避けた方がいいです。 [参考] エンタープライズ アプリケーションアーキテクチャパターン http://www.amazon.co.jp/dp/4798105538 ドメイン駆動 http://www.amazon.co.jp/dp/4798116173/ _________________ C#と諸々 | ||||||||||||
|
投稿日時: 2008-09-10 12:57
さきほど、私は、
と書きましたが、「Kokyakuクラス」が検索条件用のクラスかと勘違いしてこう書きました。
という検索に限れば「Kokyakuクラス」をそのまま検索条件用にも転用できなくもないかもしれませんが、あまりそれにこだわらないほうがよいかもしれません。 あと、
についてですが、O/Rマッピングを誰が(どのレイヤーが)担当するのかを、設計段階の最初できっちりと確定しておかないと、後から迷うことになるかもしれません。 | ||||||||||||
|
投稿日時: 2008-09-10 19:41
私が担当した物件では次のように検索部品、表示部品に分けて定義し、
ダイアログに持たせていました。 検索ボタンが押されたときに IDataSearcher.GetData メソッドでデータを取得して、 その結果を IDataViewer.ShowData メソッドに渡すようなイメージです。 リフレクションを使って DataTable から列定義を取得して、 リストビューに表示していました。 .NET2.0 以降ならジェネリックを使うといいのではないかと思います。 // データ検索インターフェース public interface IDataSearcher { // データを取得します。 DataTable GetData(); } // データ表示インターフェース public interface IDataViewer { // 指定されたデータを表示します。 void ShowData( DataTable table ); } // 顧客データ検索の基底クラス public abstract class KokyakuSearcherBase : IDataSearcher { // データを取得します。 public DataTable GetData() { // SQL文を生成してデータ取得 } // 検索SQLのwhere句を生成します。 protected abstract string BuildSqlCondition(); // 検索SQLのorderby句を生成します。 protected abstract string BuildSqlOrderColumns(); } // 顧客番号で検索 public class KokyakuSearcherByNumber : KokyakuSearcherBase { // 顧客番号 public int KokyakuNo { get; set; } // 検索SQLのwhere句を生成します。 protected override string BuildSqlCondition() { return string.Format( "KokyakuNo = {0}", + KokyakuNo ); } // 検索SQLのorderby句を生成します。 protected override string BuildSqlOrderColumns() { return "KokyakuNo"; } } 【追記】 実際には DataTable ではなく、データも独自インタフェースを用意しました。 表示された検索結果からの選択などを考えると、 キーを持たせたり、メソッドを定義したりしたかったので。 [ メッセージ編集済み 編集者: masa 編集日時 2008-09-10 19:44 ] [ メッセージ編集済み 編集者: masa 編集日時 2008-09-10 19:46 ] | ||||||||||||
|
投稿日時: 2008-09-11 12:53
皆様、アドバイス頂き大変参考になりました。
検索条件クラスを作成する方向で、まず進めていきたいと思います。 また、MVPは初めて知りましたので、どのようなものか調べてみます。 誠にありがとうございます。 |
1