- PR -

C#(オブジェクト指向)での検索画面の実装方法

1
投稿者投稿内容
かつひと
常連さん
会議室デビュー日: 2006/06/01
投稿数: 32
投稿日時: 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を使えばうまく解決できるのかもしれませんが、良い方法はありますでしょうか。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-09-10 11:55
引用:

かつひとさんの書き込み (2008-09-10 11:28) より:
 @では明らかにこれらが混在しており、大きなシステムであったり、機能変更が次々に入れば大変な労力がかかります。
Aは、余計なクラスが多くなり、かなり煩雑なクラス図になると思います。さらに、大抵DataTableインスタンスを返したりして、結局はビューとデータ層が混在する傾向にあると思います。


まず、アプリケーションは、ビジネスロジックの分離という観点から、画面がなくても動けるように作っておくほうがなにかと良いです。したがって(1)のようなハードコーディングは避けるべきです。
つぎに、「余計なクラス」というのが本当に余計なクラスならとうぜんなくしたほうが良いですが、存在させる意義があるならばクラスを作ることに躊躇する必要はないでしょう。クラス図にたくさんのクラスが登場してもやむをえないと思います。これは、クラス図を1枚の紙に詰めて書くのが難しいというだけの問題です。

引用:

かつひとさんの書き込み (2008-09-10 11:28) より:
 条件指定が「いずれか(複数可)」だと、条件が未入力かをif文で判断してSQL文を生成するか、いろんな引数のメソッドをオーバーロードする(かなりのメソッド数になる)必要があると思います。
新しいLINQを使えばうまく解決できるのかもしれませんが、良い方法はありますでしょうか。


(私は LINQ はぜんぜん知りませんが。)
「条件が未入力か」という情報を、「Kokyakuクラス」に持つほうが良いと思います。(あるいは、「Kokyakuクラス」を集約したラッパークラスにフラグを持つなどでも良いかもしれませんが。)
SQL 文の生成は、この「Kokyakuクラス」を入力としておこなうことになります。
rain
ぬし
会議室デビュー日: 2006/10/19
投稿数: 549
投稿日時: 2008-09-10 12:12
Kokyakuクラスというのはおそらく、検索結果の1件を格納するためのクラスだと思いますので、それを検索条件としても使うのはあまり賛成できません。
私だったら、検索条件を格納するためのクラスを別途用意し、それを入力にすると思います。顧客IDで範囲検索をおこないたい場合など、Kokyakuクラスでは対応しきれないと思いますし。
ちなみに条件が指定されなかった項目には、 null を入れておきます。

コード:
public class KokyakuKensakuJoken
{ 
 //顧客No(From)プロパティ 
 public Nullable<int> NoFrom
 { 
  ・・・ 
 } 
 //顧客No(To)プロパティ 
 public Nullable<int> NoTo
 { 
  ・・・ 
 } 
 //氏名プロパティ 
 public string Name 
 { 
  ・・・ 
 } 
 //住所プロパティ 
 public string Address 
 { 
  ・・・ 
 } 
} 

よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2008-09-10 12:36
引用:
かつひとさんの書き込み (2008-09-10 11:28) より:

設計やメンテを考えてできる限り、ビュー、モデル、データアクセスは分離したいと考えています。



ある意味一番重要な、MCV (Model-View-Controller) の C が抜けてます。
.NET の場合、特に MVC の亜種である MVP (Model-View-Presenter) を習得すると良いです。
ちなみに、データアクセスは M・V・P のいずれにも属しません。


引用:
かつひとさんの書き込み (2008-09-10 11:28) より:

Aは、余計なクラスが多くなり、かなり煩雑なクラス図になると思います。



レイヤー分けをして、クラス毎のアクセス修飾子を適切に設定 (無駄に public にしない) してやれば、
あとはクラス図の書き方次第で見やすくなるでしょう。


引用:
かつひとさんの書き込み (2008-09-10 11:28) より:

条件指定が「いずれか(複数可)」だと、条件が未入力かをif文で判断してSQL文を生成するか、いろんな引数のメソッドをオーバーロードする(かなりのメソッド数になる)必要があると思います。



複雑な検索条件を表現したい場合、検索条件をクラス化すると良いかと思います。
ただし、過度な作りこみは避けた方がいいです。


[参考]
エンタープライズ アプリケーションアーキテクチャパターン
http://www.amazon.co.jp/dp/4798105538
ドメイン駆動
http://www.amazon.co.jp/dp/4798116173/

_________________
C#と諸々
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-09-10 12:57
さきほど、私は、
引用:

unibonさんの書き込み (2008-09-10 11:55) より:
「条件が未入力か」という情報を、「Kokyakuクラス」に持つほうが良いと思います。(あるいは、「Kokyakuクラス」を集約したラッパークラスにフラグを持つなどでも良いかもしれませんが。)
SQL 文の生成は、この「Kokyakuクラス」を入力としておこなうことになります。


と書きましたが、「Kokyakuクラス」が検索条件用のクラスかと勘違いしてこう書きました。

引用:

かつひとさんの書き込み (2008-09-10 11:28) より:
 検索画面では、顧客No、氏名、住所の「いずれか(複数可)」を条件にして検索するという仕様だったとすると、一般的(雑誌や書籍)には以下のような実装方法が多いと思うのですが、


という検索に限れば「Kokyakuクラス」をそのまま検索条件用にも転用できなくもないかもしれませんが、あまりそれにこだわらないほうがよいかもしれません。

あと、
引用:

かつひとさんの書き込み (2008-09-10 11:28) より:
Aは、余計なクラスが多くなり、かなり煩雑なクラス図になると思います。さらに、大抵DataTableインスタンスを返したりして、結局はビューとデータ層が混在する傾向にあると思います。


についてですが、O/Rマッピングを誰が(どのレイヤーが)担当するのかを、設計段階の最初できっちりと確定しておかないと、後から迷うことになるかもしれません。
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 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 ]
かつひと
常連さん
会議室デビュー日: 2006/06/01
投稿数: 32
投稿日時: 2008-09-11 12:53
 皆様、アドバイス頂き大変参考になりました。

 検索条件クラスを作成する方向で、まず進めていきたいと思います。
また、MVPは初めて知りましたので、どのようなものか調べてみます。
誠にありがとうございます。
1

スキルアップ/キャリアアップ(JOB@IT)