- PR -

クラス設計の基本的質問:プロパティ経由で受け取ったリソースの破棄

投稿者投稿内容
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2007-01-31 19:01
8ヶ月ほど前に、同じことをやった気がする。
私は、破棄することを放棄しました。ASP.NETなので、Pageオブジェクトが破棄されたら、参照が外れて、そのうち破棄されるだろう..


真似しないほうがいいと思う(ノ_-;)
_________________
KI
大ベテラン
会議室デビュー日: 2007/01/10
投稿数: 239
投稿日時: 2007-01-31 20:49
Penに限った話ではないですが、newしたオブジェクトを、
別のクラスのインスタンスにプロパティ経由で渡し、
そのインスタンスが破棄されたときに渡したオブジェクトも
一緒に破棄されるというのに、私は違和感を覚えます。
やはりnewした側が責任を持つべきな気がします。

1つの案ですが…こんなのはどうでしょう?

描画に使用するPenやらBrushやらをコンストラクタで生成して、
内部フィールドに格納。Dispose内でそれらをDisposeします。
そして、PenとかBrushは外部にreadonlyのプロパティとして公開。
使う側はそのプロパティを参照してPenのColorやWidthのような
プロパティを必要に応じて変更する。
Dustin
会議室デビュー日: 2007/01/30
投稿数: 7
投稿日時: 2007-01-31 20:54
皆様ありがとうございます。
おかげさまで
引用:

C++ の new と delete と同じで「生成した者が破棄の責任を持つ」


の原則をようやく呑み込めたように思います。

確認のため
現時点の私の認識を述べさせていただきます。
ここで、仮に、コンストラクタ・プロパティ等を経由して外部からリソースへの
参照を渡されるクラスがあるものとします。
このクラスの設計について、以下のようにあるべきであると認識します。
・外部からリソースへの参照を渡されるにしても、そのリソースの破棄は
 原則としてそのリソースを生成した者の責任である。
・このクラスのコンストラクタ内・メソッド内で、このクラス自身が生成した
 リソースについては、当然このクラスが破棄の責任を持つ。また、必要に応じて
 IDisposableを実装すべきである。
・↑の理由でIDisposableを実装した場合、このクラスのDispose()では、
 外部から参照を渡されたリソースの破棄については、くどいようであるが
 このクラスの責任範囲外であり、リソース生成者が破棄すべきである。

・・・こうしてみますと、実に初歩的なことだったのかもしれません。お恥ずかしい;;

(強いて述べますと、上記の設計でIDisposableを実装した場合、そのクラスのDispose()が
外部リソースの破棄まで負ってくれるものとユーザが誤解する可能性は残るような
気はいたします
# と このように述べましたが、そんな誤解しないですよね。すみません。
)


以上の認識に従いまして、冒頭のTBorderクラス他 外部からリソースを渡される
クラスについては、そのリソースの破棄の責任を負わないことにいたします。

仮にユーザが
コード:

graph.Border.Pen = new Pen(...);


のようなコードを書いて、リソースの破棄をGC任せにするとしても、
それはユーザの勝手とします。
これでユーザにリソースの破棄について選択の自由が生まれました。

私自身はPHPなどスクリプト言語での開発が長いためか、
私の意識がリソースの管理について非常にルーズであることがわかりました。

ベテランの方々のご助言をいただけまして助かりました。


[ メッセージ編集済み 編集者: Dustin 編集日時 2007-01-31 21:04 ]
Dustin
会議室デビュー日: 2007/01/30
投稿数: 7
投稿日時: 2007-01-31 21:41
引用:

この場合、graphクラスは描画する際に使用するPenの情報だけ保持して
Draw()で保持していうPenの情報を元にPenを作成して、Draw()終了時
に破棄すればよいのではないでしょうか


ご指摘ありがとうございます。
”描画する際に使用するPenの情報だけ保持して”というのは、
例えば線を引くのに必要な情報(色や太さなど)をフィールドとして持つ構造体を定義して
graphクラスがその構造体を持つ、あるいは直接graphクラスがフィールドとしてそのような情報を
持つことを意味していると認識いたしましたが、正しいでしょうか。

コード:
/// <summary>ペンの情報を保持する構造体</summary>
/// <remarks>型名の接頭辞の不恰好な点はご容赦を</remarks>
public
struct  ST_Pen {
	public Color  Color;
	public float  Width;
	
	public
	ST_Pen( Color  color ) {
		this.Color = color;
		this.Width = 1;
	}
	public
	ST_Pen( Color  color, float  w ) {
		this.Color = color;
		this.Width = w;
	}
}

/// <summary>何かを描画するクラス</summary>
/// <remarks>
///     どんな形であれリソースを保持しないのでIDisposeの実装の
///     必要性はなくなりました。
/// </remarks>
public sealed
class  THoge {
	private ST_Pen  _pen;
	
	public
	ST_Pen  Pen {
		get { return  _pen; }
		set { _pen = value; }
	}
	
	/// <summary>何かを描画します。</summary>
	/// <param name="g">グラフィックハンドル</param>
	public
	void  Draw( Graphics  g ) {
		using( Pen  pen = new Pen(_pen.Color, _pen.Width) ) {
			g.DrawLine( pen, 10, 10, 20, 20 );
		}
	}
}



// 以下はユーザ側のコード
Bitmap        img;
MemoryStream  o;

img = new Bitmap( 200, 200 );
using( Graphics  g = Graphics.FromImage(img) ) {
	g.Clear( Color.White );

	THoge  hoge = new THoge();
	hoge.Pen = new ST_Pen( Color.Red, 2 );
	hoge.Draw( g );
}

Response.ContentType = "image/png";
o = new MemoryStream();
img.Save( o, ImageFormat.Png );
o.WriteTo( Response.OutputStream );
img.Dispose();


渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2007-02-01 01:24
引用:

このクラスの設計について、以下のようにあるべきであると認識します。
(略)
・・・こうしてみますと、実に初歩的なことだったのかもしれません。お恥ずかしい;;



「今回はその方がいいかもね」というだけであって、常にそのシナリオが妥当であるというわけではありません。「委譲」のパターンも存在します。

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