- PR -

オブジェクトが特定のプロパティを持っているか調べる方法

投稿者投稿内容
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-09-28 14:21
>継承という強力な武器を持っているのに、型チェックするというのはやはり勿体無い気がしますね。

最初は継承構造でうまくいっていたのですが、だんだんうまくいかなくなってきました。

たとえばこんなことです。

描画クラスから文字枠のクラスと絵のクラスを派生しました。

絵のクラスからタイトルとふちのある絵を派生しました。

絵のクラスは背景色を持ちませんが、
タイトルとふちのある絵のクラスは背景色を持ちます。

どうしても継承構造とは関係なく背景色を塗ることのできるという
インタフェースのチェックが必要になります。

で、この例の場合は背景色という単純なパターンなので、
タイトルとふちのある絵のクラスに内在クラス?として
文字枠のクラスを作ってそれがドロップ操作を受け取るなんてことでよいのですが
論理的な意味合いをもつオブジェクトだとなかなかそういうわけにはいかなくなるんです。

的確な実例を示せずに申し訳ありません。

そもそも、特定のプロパティをチェックするというのは、たまたま特定のプロパティが
そういう役割を持っていたから、安直に考えたに過ぎなくて
その目的からいって完全に間違った方法であるわけです。おはずかしい。
きちんとインタフェースを定義していこうと思っています。

いろいろありがとうございました。
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-09-28 15:48
ジブです。

本論とは関係ないのですが
先ほどの複数インタフェースを持つかどうかのコードに誤りがありましたので
訂正いたします。

Public Shared Function InterfaceCheck(ByVal obj As Object, ByVal Types() As Type) As Boolean

  Dim t_Type As System.Type

  If obj Is Nothing Then
    Return False
  End If

  For Each t_Type In Types
    If t_Type.IsAssignableFrom(obj.GetType) Then
      Return True
    End If
  Next
  Return False

End Function

です。Equalsでは、だめなんですね。
失礼しました。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-09-28 20:26
引用:

ジブさんの書き込み(2005-09-28 14:21)より:

描画クラスから文字枠のクラスと絵のクラスを派生しました。

絵のクラスからタイトルとふちのある絵を派生しました。

絵のクラスは背景色を持ちませんが、
タイトルとふちのある絵のクラスは背景色を持ちます。

どうしても継承構造とは関係なく背景色を塗ることのできるという
インタフェースのチェックが必要になります。


むむ?
 “描画クラス”が、“背景色プロパティ”を持っているべきでは?
 “絵クラス”に“背景色プロパティ”が不要なら、無視してしまえばいいだけでは?
 または、“透明色”のある“絵”であれば、“背景色プロパティ”が必要なのでは?
_____________________________________________________________________________
□ Posted by Jitta on 2005/09/28
じったのノート
□ Microsoft MVP :Visual Developer ASP/ASP.NET Oct.2004-Sept.2005

_________________
検索のコツ質問のコツ

[ メッセージ編集済み 編集者: Jitta 編集日時 2005-09-28 20:27 ]
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-10-01 12:41
じったさん、みなさんこんにちは。

どうも私の示した例はうまい例ではなかったみたいです。
(実際、私のケースですと描画クラスは背景色を持っているのですが
最初にBackColorなどを例にしてしまったので、無理やり例を考えてみたのです)

でも他にうまい例え話も思いつかないのでそのまま進めたいと思います。
今回の例で皆様だったらどのように実装されるのか興味があったりします。

さて、私だったらですが
引用:

“描画クラス”が、“背景色プロパティ”を持っているべきでは?


”線”なんかもあるわけで、中間のクラスが必要なのかな。
なにより基本の基本クラスは出来るだけ簡素にしたいです。

引用:

 “絵クラス”に“背景色プロパティ”が不要なら、無視してしまえばいいだけでは?


はい。無視というより無効にというかシャドーするケースは多いです。
その場合、有効か無効かを個別ではなく目的別に知る手段として
インタフェースの概念はとても有効であると思っています。

引用:

 または、“透明色”のある“絵”であれば、“背景色プロパティ”が必要なのでは?


“透明色”のある“絵”であれば、背景色を塗ってはいけないはずです。
コンテナの色が消えてしまいますから。

いかがなものでしょうか

[ メッセージ編集済み 編集者: ジブ 編集日時 2005-10-01 12:43 ]
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2005-10-01 16:52
それはオブジェクト思考設計がまずいですよ。外部でオブジェクトの種類や状態を意識しなくてはならなくなるという事は、設計の基本となるはずのカプセル化が不十分だと言うことです。

オブジェクトの種類や方を調べて描画の仕方を変えるのではなく、描画の仕方を含むオブジェクト固有のものをクラスの中にカプセル化する様に考えないと。私ならDraw(graphics g)と言うメソッドをひとつ用意して、そのクラスに描画に関する処理も収めます。どうしてもデータと描画を分離したいなら、描画を行うクラスを生成するBuilderインターフェースを作ります。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2005-10-01 17:18
こんにちは。

今回の例の場合、「描画クラス」というのが描画関係クラス全部のスーパークラスになっているわけですね。

「描画クラス」から、「線」「文字枠」「絵」といったクラスができるわけですね。
このような階層になるならば、「描画クラス」に背景色プロパティを持たせることは不自然であることも納得できます。

「描画クラス」は「描画する」といった「振る舞い」を持ち、属性は基本的に持たない方向でどうでしょうか。もちろん、「基本的な描画をする」という行為に必要であれば「描画クラス」に持たせれば良いでしょう。

「線クラス」を扱うクライアントは、「線」を初期化するときは、「線クラス」を扱っているということを分かっているはずです。
「線」に太さや、スタイルといった属性を設定できるでしょう。

で、描画を行うクライアントは、今描画しようとしているオブジェクトが「描画クラス」であることは分かっても、「線クラス」であることは知りません。
しかし、「線クラス」自身は、自分自身の描画の仕方を知っています。
だから、描画を行うクライアントは、「描画する」という振る舞いを呼び出すだけで、「線クラス」の事は知らなくても、描画できます。

「背景色が塗ることができるクラス」であるとか「ふちを描画できるクラス」であるとかは、クライアントにしたら知っちゃ事ではないわけです。
判断する必要もありません。

クライアントは「描画できる」という事のみ知ればよい、という事です。

コード:
public abstract class DrawObject
{
	// 描画オブジェクトの位置
	public int X;
	public int Y;

	public void abstract Draw();
}

public class Line : DrawObject
{
	pubic int Length;
	public int Width;

	public void override Draw()
	{
		// 線を描きます
	}
}

public class Picture : DrawObject
{
	public Color BackColor;
	public int Heigth;
	public int Width;	// <- 「Line.Widht」と概念とは別物

	public void override Draw()
	{
		// 絵を描きます
	}
}

public class EdgingPicture : Picture
・・・



ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-10-01 18:11
こんにちは。ジブです。

甕星さん
引用:

オブジェクトの種類や方を調べて描画の仕方を変えるのではなく、描画の仕方を含むオブジェクト固有のものをクラスの中にカプセル化する様に考えないと。私ならDraw(graphics g)と言うメソッドをひとつ用意して、そのクラスに描画に関する処理も収めます。どうしてもデータと描画を分離したいなら、描画を行うクラスを生成するBuilderインターフェースを作ります。


IPaintableとかいういうインタフェースを作り、そこにPaintメソッドを定義
基本クラスは抽象クラスにしてIPaintableをインプリメントする
そんな感じになっています。

囚人さん
引用:

「背景色が塗ることができるクラス」であるとか「ふちを描画できるクラス」であるとかは、クライアントにしたら知っちゃ事ではないわけです。
判断する必要もありません。


はい。もちろんクライアントには関係ない話です。friendな世界の話です。

引用:

クライアントは「描画できる」という事のみ知ればよい、という事です。



内部のツールでは「描画できる」かどうか判断の必要はありませんが
「バックグラウンドを塗れる」かの判断が必要になります。

例えばIPaintableCollectionは「描画できる」オブジェクトを管理していますが
そのなかで「バックグラウンドを塗る」ツールがそのItemtが
「バックグラウンドを塗れる」かを判断しなければなりません。

マウスポジションのヒットテストを実施して「バックグラウンドを塗れる」となれば
そういうシグナルをユーザーに示したいと考えています。

例えばイメージとしては、こんな感じです。

コード:
	Friend Function HitTestIPaintBackroundAble( うんちゃらかんちゃら) as (例えば)Boolean
		For Each item as IPaintable In myPaintableCollection
			If TypeOf item Is IPaintBackroundAble then
				CType(item,IPaintBackroundAble).HitTestSignal = True
			End If
		Next
	End Function



あとからペイントの処理で

コード:
	Sub Paint(うんちゃらかんちゃら)  Implements うんちゃらかんちゃら
		For Each item as IPaintable In myPaintableCollection
			item.Paint(うんちゃらかんちゃら)
		Next
	End Function



こんなイメージなんですが、ご意見をいただけますでしょうか
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2005-10-01 18:51
引用:

はい。もちろんクライアントには関係ない話です。friendな世界の話です。


これはどういう意味でしょう?

引用:

内部のツールでは「描画できる」かどうか判断の必要はありませんが
「バックグラウンドを塗れる」かの判断が必要になります。



「描画できる」の判断ではなく、IPaintable だから、判断する必要もなく全て「描画できる」です。

どうしても「バックグラウンドを塗れる」かどうかの判断をしたいのであれば、IPaintable が判断しなくてはいけないでしょう。(IPaintable に対して行っているから)

コード:

foreach( IPaintable item in myPaintableCollection )
{
if( item.EnablePaintBackGround )
{
// バックグラウンドを塗れる!
}
}



各派生クラスは、EnablePaintBackGround をオーバーライドして、「バックグラウンドを塗れる」かどうかを返せばよいです。

#編集
C# になって申し訳ないです。VB は書き慣れていないもので^^;



[ メッセージ編集済み 編集者: 囚人 編集日時 2005-10-01 18:54 ]

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