DOBON.NET DOBON.NETプログラミング掲示板過去ログ

派生先でプロパティが増え、処理が増えるメソッドの実装方法

環境/言語:[OS : Windows XP Home Edition / 言語 : Visual Basic 2005 / .NET Framework : 2.0]
分類:[.NET]

【解決したい問題】

こんばんは、しろひとです。
質問があります。

●作りたいプログラム
 今、オリジナルの TreeNode クラスを作って TreeView に様々なタイプの TreeNode を表示させるプログラムを組んでいます。Windows のエクスプローラーのように左ペインで TreeView を表示させ TreeNode を選択し、選択された TreeNode の持つプロパティが右ペインに表示されます。また、「保存」を行うと、TreeView に含まれる全ての TreeNode (トップノードから末端のノードまで)のプロパティ値がテキストファイルに保存され、次回「読込み」時に同じ TreeView が作られます。

●実現させるための仕組み
 まず、Windows.Forms.TreeNode クラスを継承する TreeNodeEx クラスを作成します。TreeNodeEx クラスには、.save() メソッド、.load() メソッドがあります。全てのノードは、この TreeNodeEx クラスを継承します。あるノードの .save() メソッドを実行すると、そのノードのプロパティ値をテキストファイルへ書き出し、続いてそのノードに含まれる全ての子ノードの .save() メソッドを呼び出します。これにより、トップノードの .save() メソッドを呼び出せば、TreeView 内全てのノードの .save() メソッドが呼び出されます。このように階層的に .save() メソッドを実行することで、全ての TreeNode がテキストファイルに保存されます。同様に.load() メソッドではテキストファイルから値を読込み、階層的に TreeNode の作成を行います。
 全ての TreeNode クラスは TreeNodeEx クラスを継承していますが、そこから更に派生した孫世代の TreeNode クラスもあります。派生する度に プロパティが追加されていきます。

●現時点での問題
 TreeNodeEx クラスから派生した TreeNode動物 クラスでは、プロパティの種類が増えています。従って、TreeNode動物 クラスの save() メソッドでは、保存を行うプロパティの数が増えます。また、TreeNode動物 クラスから派生した TreeNode犬 クラスでは、更にプロパティが増えており、save() メソッドの処理内容もその分増えます。
 このように、派生する毎に保存項目が増える save()メソッドを記述したいのですが、save() メソッドそのものをオーバーライドしてしまうと、派生元のクラスが仕様変更された場合(プロパティの種類が増減した場合)、それを継承する全てのクラスでコードを書き直さなければならなくなります。それを避けるために、派生先のクラスの save() メソッドでは追加的にコードを記述したいのですが、そういった方法はあるのでしょうか。

●クラスの例
・Exクラス・・・Windows.Forms.TreeNode クラスから派生したクラス。save()、load()メソッドを持つ。
・動物クラス・・・Exクラスから派生したクラス。頭・胴体プロパティを持つ。
・犬クラス・・・動物クラスから派生したクラス。前足・後ろ足・尻尾プロパティを持つ。
・鳥クラス・・・動物クラスから派生したクラス。羽・足プロパティを持つ。

 動物クラスの save() メソッドでは、頭・胴体プロパティの保存を行います。
 犬クラスの save() メソッドでは、頭・胴体・前足・後ろ足・尻尾プロパティの保存を行います。

●自分なりに考えたコード
TreeNodeEx クラス、派生した TreeNode動物 クラス、更に動物クラスから派生したTreeNode犬クラスの各 save メソッドについて

Class TreeNodeEx Inherits Windows.Forms.TreeNode

Public Sub save()
・TreeNodeEx クラスの各プロパティ(.text等)の保存
・save2() の呼び出し
End Sub

Private Sub save2() Overridable
 空欄(派生先でオーバーライド用)
End Sub

End Class


Class TreeNode動物クラス Inherits TreeNodeEx

Private Sub save2() Overrides
 ・動物クラス独自のプロパティ(頭・胴体)の保存
 ・save3() の呼び出し
End Sub

Private Sub save3() Overridable
 空欄(派生先でのオーバーライド用)
 (犬クラス・鳥クラス等でオーバーライドされる)
End Sub

End Class


Class TreeNode犬クラス Inherits TreeNode動物

Private Sub save3() Overrides
 ・犬クラス独自のプロパティ(前足・後ろ足・尻尾)の保存
 ・save4() の呼び出し
End Sub

Private Sub save4() Overridable
 空欄(派生先でオーバーライド用)
End Sub

End Class

以上のようにすると、save 機能の部分的なオーバーライドが可能ですが、コードが煩雑になってしまうのと、後にクラスを派生して使いたい場合、上記の仕組みにのっとって Overridable なプロシージャを Overrides し、またそこから派生先のための空のプロシージャを用意しておかなければなりません。できれば、以下のように追加するコードが単純化すればよいのですが・・・

Ex クラス
sub save1()
Exプロパティの保存
end sub

動物クラス Inherits Exクラス
sub save2()
動物プロパティの保存
end sub

犬クラス Inherits 動物クラス
sub save3()
 犬プロパティの保存
end sub

クラスを呼び出すコード側で、クラス内の save に関するメソッド(犬クラスの場合、save1〜3メソッド)をまとめて呼び出す方法等、ありませんでしょうか。
SaveメソッドをOverridableにして、
オーバーライドするメソッドで親のSaveメソッドを呼び出せば
よいのではないでしょうか?

Public Overrides Sub Save()
MyBase.Save()
そのクラス独自のプロパティ保存ロジックを追加
End Sub
2006/04/09(Sun) 19:55:55 編集(投稿者)

>よねKEN様

ご教授ありがとうございます!
大変勉強になりました。

ご教授頂いた通りの方法で、すっきりしたコードが組めそうです。

クラス内でオーバーライドを行っても、MyBase キーワードを使えばオーバーライドされる前の状態を呼び出すことができるのですね。MyBase キーワードを使えば、クラスの親元をたどることができ、クラスの継承・派生の関係を立体的に扱うことができるのですね。

ご教授頂いた方法で、クラスの派生に伴い、メソッドの処理をスムーズに増やしていくことができそうです。

気になるのは、もし私の質問に対して、「MyBase キーワードを使いなさい」と
一言言われただけだったとしたら、ご教授頂いた通りのコードを思いつくに至ったかどうか。
プログラミングは奥が深くて面白いですね。
解決済み!
■No15265に返信(しろひとさんの記事)
> クラス内でオーバーライドを行っても、MyBase キーワードを使えばオーバーライドされる前の状態を呼び出すことができるのですね。
> MyBase キーワードを使えば、クラスの親元をたどることができ、クラスの継承・派生の関係を立体的に扱うことができるのですね。

というよりは、個人的には、オーバーライドする場合は、MyBase、
つまり基底クラスのメソッドが呼び出されるような構造にすべきだと思います。

Shadows であれば無視することもありますが。

....................................................................
http://jeanne.wankuma.com/
http://blogs.wankuma.com/jeanne/
解決済み!
■No15271に返信(じゃんぬねっとさんの記事)
> というよりは、個人的には、オーバーライドする場合は、MyBase、
> つまり基底クラスのメソッドが呼び出されるような構造にすべきだと思います。
>
> Shadows であれば無視することもありますが。

 なるほど。
 メソッドのオーバーライドを定義する際、
 IDE ( Visual Basic 2005 ) の機能によって自動的に MyBase.メソッド を
 呼び出すコードが追加されました。
 これは、MyBase メソッドが呼び出されるような構造を暗黙的に
 推奨しているのでしょうか。

 確かに、クラスを派生させるということは、
 定義・機能の「上書き」というよりも、「追加」というイメージがあります。
 (その方がクラスの親子関係をスムーズに理解できる気がしています。)

 もちろん、「追加」だけでなく「上書き」もできた方が
 プログラムを書く上で表現が豊かになりますが。
 私はまだ経験が浅いですが、クラスを設計する際にはきちんと計画を練って
 考えたいと思います。

 ご教授ありがとうございました。

P.S.
 オーバーライドしたメソッドは暗黙的に overridable なんですね。
 オーバーライドしたものを更にオーバーライドする際、どうしたらいいか
 少し悩みました。
  Public Overridable Overrides Sub メソッド()
 なんて記述して、IDE から注意されました。これは、
  Public Overrides Sub メソッド()
 と書けば暗黙的に Overridable の意味も持つのですね。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板