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

静的かつ抽象なメンバについて

環境/言語:[Windows2003/VB.NET、.NET Frameworkのバージョン1.1]
分類:[.NET]

2005/10/07(Fri) 13:29:26 編集(投稿者)

こんにちは。キムラと申します。

早速本題なのですが、

たとえば、
各種TableClassを実装するために、
まず、MustInheritなTableBaseClassを書きます。
TableBaseClassには、Delete文を実行する汎用的なメソッドを実装します。

Delete文を実行するためには、PrimaryKeyが必要です。
しかし、TableBaseClassとしてはPrimaryKeyをわからないので、
MustOverrideと宣言して、Delete文を実装し、
かつ、子クラスでの実装もれをなくしたい。

しかし、各種TableClassからすればPrimariKeyは、
インスタンスに依存しないクラス固有(テーブル固有)なものですし、
Sharedと宣言し、Newしなくても読み出したい。

これを実装したいと思ってること自体おかしいのでしょうか?
皆様の知恵や指摘をお借りしたいです。
よろしくお願いします。

キムラ
2005/10/07(Fri) 13:38:52 編集(投稿者)

お世話になります。

■No13149に返信(キムラさんの記事)
> しかし、各種TableClassからすればPrimariKeyは、
> インスタンスに依存しないクラス固有(テーブル固有)なものですし、
> Sharedと宣言し、Newしなくても読み出したい。

読み出すのは、各種TableClass自身なわけですよね?
Sharedでなく、Constにするのは駄目ですか?
> 各種TableClassを実装するために、
> まず、MustInheritなTableBaseClassを書きます。
> TableBaseClassには、Delete文を実行する汎用的なメソッドを実装します。
>
> Delete文を実行するためには、PrimaryKeyが必要です。
> しかし、TableBaseClassとしてはPrimaryKeyをわからないので、
> MustOverrideと宣言して、Delete文を実装し、
> かつ、子クラスでの実装もれをなくしたい。

MustOverrideなのでインターフェースの記述漏れはコンパイルエラーになり漏れは防げます。
ただし中身の漏れは防げません。

> しかし、各種TableClassからすればPrimariKeyは、
> インスタンスに依存しないクラス固有(テーブル固有)なものですし、
> Sharedと宣言し、Newしなくても読み出したい。

そのクラス名を記述することに妥協すればSharedでよいのでは?
返信ありがとうございます。

■No13150に返信(なおこ(・∀・)さんの記事)
> 読み出すのは、各種TableClass自身なわけですよね?
> Sharedでなく、Constにするのは駄目ですか?

各種TableClassでConst宣言するということは、
BaseTableClassでPrimariKeyを呼び出すメンバを実装しないということですか?

それだと、Delete文がBaseTableClassで実装できないので困るのです...
こんにちは、じゃんぬ です。

Shread ReadOnly なメンバにして、静的コンストラクタでインスタンス化して保証するとか。
お世話になります。

■No13157に返信(キムラさんの記事)

こういうのはどうしょうか。
●BaseTableClass
Public MustOverride GetDeleteSQL(keyvalue As String) As String
としておいて、

●各TableClass
Public Overrides GetDeleteSQL(keyvalue As String) As String
…Delete文を作成する実装
>>Sharedと宣言し、Newしなくても読み出したい。
>
> そのクラス名を記述することに妥協すればSharedでよいのでは?

すいません、Deleteと切り離して考えてしまいしました。
■No13156に返信(まどかさんの記事)
> MustOverrideなのでインターフェースの記述漏れはコンパイルエラーになり漏れは防げます。
> ただし中身の漏れは防げません。

記述漏れはともかく、中身の漏れはなしの方向でお願いします。
これはプログラマ(人)としての問題な気がするので...

> そのクラス名を記述することに妥協すればSharedでよいのでは?
Sharedで空のメソッドを宣言し、Shadowsで上書きするということでしょうか?

これが最適な妥協点と、私も思っていました。
(最初の投稿に書いてないですけど...)

ですが、オーバーライドの最適化と、記述漏れを未然に防ぐことを
妥協しない方法があるのかもと思い悩んでいます。

キムラ
■No13158に返信(じゃんぬねっとさんの記事)

> Shread ReadOnly なメンバにして、静的コンストラクタでインスタンス化して保証するとか。

親クラスで、
Public Shared ReadOnly PrimaryKey As String
と宣言し、子クラスで、
Shared Sub New()
PrimaryKey = "ID"
End Sub
は、違反ですよね?

私の理解がおかしいのでしょうか...
> 記述漏れはともかく、中身の漏れはなしの方向でお願いします。

中身(実装)をMustにする方法は無いでしょう。

SharedをMust〜にできない限り、
Deleteの実装内でSharedメンバを人間が意識して記述することになりませんか。
■No13159に返信(なおこ(・∀・)さんの記事)
> ●BaseTableClass
> Public MustOverride GetDeleteSQL(keyvalue As String) As String
> としておいて、
>
> ●各TableClass
> Public Overrides GetDeleteSQL(keyvalue As String) As String
> …Delete文を作成する実装

これ自体はまったく持って問題ないと思うのです。

ただ、汎用的なDeleteとして、
. Public Sub DoDeletion(ByVal id As Integer)
. _sqlCommand.CommandText = (" Delete From " & TableName _
. & " Where " & PrimariKey & " = " & "@" & PrimariKey )

. _sqlCommand.Parameters.Clear()
. _sqlCommand.Parameters.Add("@" & PrimariKey, id)
. End Sub
を親のクラスに実装したかったのです。
やはり、このメソッドを各種TableClassに実装すべきでしょうか...

※TableNameは、PrimariKeyと実装方法は同じと考えてください。
※PrimariKeyが複数の場合に対応する必要性は、認識しております。
お世話になります。

■No13165に返信(キムラさんの記事)
ではこんな感じはいかがでしょう。

●親クラス
 Protected MustOverride ReadOnly Property TableName As String
 Protected MustOverride ReadOnly Property PrimariKey As String

Public Overridable Sub DoDeletion(ByVal id As Integer)
_sqlCommand.CommandText = (" Delete From " & TableName _
& " Where " & PrimariKey & " = " & "@" & PrimariKey )

_sqlCommand.Parameters.Clear()
_sqlCommand.Parameters.Add("@" & PrimariKey, id)
End Sub
 

●子クラス
 Protected Overrides ReadOnly Property TableName As String
   Get
     Return "テーブル名"
   End Get
 End Property

 Protected Overrides ReadOnly Property PrimariKey As String
   Get
     Return "キー"
   End Get
 End Property
■No13164に返信(まどかさんの記事)
>>記述漏れはともかく、中身の漏れはなしの方向でお願いします。
>
> 中身(実装)をMustにする方法は無いでしょう。

説明が足りなかったようですね、すみません。

記述漏れはともかく:
MustOverrideとすればコンパイルできないので実装してくれる。

中身の漏れはなし:
Private Overrides Sub PrimariyKey()
’中身を書かない
End Sub
としてもコンパイルはできる。ここまできて中身を書かないという前提はなしの方向。

ということが言いたかったのです...
というか私の読解間違いですかね、失礼しました。

> SharedをMust〜にできない限り、
> Deleteの実装内でSharedメンバを人間が意識して記述することになりませんか。

そうですね、人間が意識して記述することを促す、
コンパイルエラーで示すという意味で、
Private MustOverride Sub PrimariyKey()
というようにし、
Private Overrides Sub PrimariyKey()

End Sub
ここまで書かせることによって、中身が必要だと認識させたかったのです。

VB.NETをまだ数ヶ月しか触っていないので(それを免罪符にするつもりは毛頭ありませんが)、少しそれを踏まえたうえで私の発言を疑っていただければと思います。
よろしくお願いします。

キムラ
2005/10/07(Fri) 15:15:50 編集(投稿者)

■No13166に返信(なおこ(・∀・)さんの記事)
> ●親クラス
>  Protected MustOverride ReadOnly Property TableName As String
>  Protected MustOverride ReadOnly Property PrimariKey As String
>                .
>                .
>                .

これだと、

■私の一番最初の書き込みより引用
> しかし、各種TableClassからすればPrimariKeyは、
> インスタンスに依存しないクラス固有(テーブル固有)なものですし、
> Sharedと宣言し、Newしなくても読み出したい。

「インスタンスしなくても読み出したい」は、無理ということでしょうか?
> ただ、汎用的なDeleteとして、
> ・・・・・
> 親のクラスに実装したかったのです。

なおこさんご提示のように
MustOverride Function GetPrimaryKeys()を親に実装、
継承先のGetPrimaryKeysはSharedメンバの値を返す。
ということになるかな?

>このメソッドを各種TableClassに実装すべきでしょうか...

使い方の位置づけはわかりませんが、
抽象クラスでクローズできるもの(コネクションなど)のみの実装にして
そこからベストなものを考えていけばよいのではないでしょうか。
追加変更方法として、実装の変更とOverLoadがありますし。
> VB.NETをまだ数ヶ月しか触っていないので(それを免罪符にするつもりは毛頭ありませんが)、少しそれを踏まえたうえで私の発言を疑っていただければと思います。

いやいや、ご心配しているようなことはありませんので。

であれば、
>抽象クラスでクローズできるもの(コネクションなど)のみの実装にして
を基本にするといいと思います。
親は子を知らないという大前提を守るということです。
お世話になります。

■No13170に返信(キムラさんの記事)
> 「インスタンスしなくても読み出したい」は、無理ということでしょうか?
あのままですとそうなります。

Protected MustOverride

Protected Sharedとして、子クラスでShadowsになるでしょう。
しかし、既出の通り、子クラスにプロパティ実装を強要できませんよね。

親のDoDeletionはインスタンスメンバ関数として持っていますよね?
これもSharedと宣言すると、
子クラスで実装する場合、Shadowsとしないといけないですよね。

せっかく抽象親クラスを持つのなら、
その抽象のメリットを生かすべきだと思うのですが。
■No13171に返信(まどかさんの記事)
> なおこさんご提示のように
> MustOverride Function GetPrimaryKeys()を親に実装、
> 継承先のGetPrimaryKeysはSharedメンバの値を返す。
> ということになるかな?

この場合だと、
Private Shared _prinmaryKey As String
の記述が必要だということを、MustOverrideのように明示は、
できないということでしょうか?

> >このメソッドを各種TableClassに実装すべきでしょうか...
>
> 使い方の位置づけはわかりませんが、
> 抽象クラスでクローズできるもの(コネクションなど)のみの実装にして
> そこからベストなものを考えていけばよいのではないでしょうか。
> 追加変更方法として、実装の変更とOverLoadがありますし。

一例ではありますが、この、
Public Overridable Sub DoDeletion(ByVal id As Integer)
を親のクラスで記述するか、しないかで子クラスでの記述量が、
変わってくるという意味で「実装すべきでしょうか」といいたかったのです。
できる限り抽象化し、親のクラスで実装したいという意味です。

さらに、Overloadとありますが抽象化できる限り、この引数以外のものも
親クラスもしくは、現在示している親子の間の中間的なクラスに
実装するということは、認識していると踏まえていただきたいです。

キムラ
■No13172に返信(まどかさんの記事)
> 親は子を知らないという大前提を守るということです。

ということは親のクラスが、「子クラスの機能であるDelete文」や
「子クラスがPrimaryKeyを持っている」ということを前提にして記述しては、
いけないということでしょうか?

よろしくお願いします。
キムラ
> ということは親のクラスが、「子クラスの機能であるDelete文」や
> 「子クラスがPrimaryKeyを持っている」ということを前提にして記述しては、
> いけないということでしょうか?

抽象クラスですからそれが単独(自身でクローズ)で存在しないといけません。
#必ず継承されるわけではないし、抽象クラスだけが存在する場合を考えてみてください。

>できる限り抽象化し、親のクラスで実装したいという意味です。

上記から言えば、抽象化すればするほど親だけでクローズしていきますよね。
#というか、クローズされていなければ抽象化されてないということになる。

ということは、親に実装ロジックがあることと、キーが子に依存する情報であることは
互いに矛盾することになります。
これを実現するなら、親が子を知る必要があるが、子のみの情報を知ることはできないので
親がインターフェースを持つ必要があり、かつ親に実装、つまり、なおこさんご提示のように
DeleteはOverridable、キーの情報をMustOverrideにするしかないでしょう。
そして、Overrideした子のキー情報はSharedメンバの値を返せばよいかと思います。
■No13177に返信(まどかさんの記事)
> ということは、親に実装ロジックがあることと、キーが子に依存する情報であることは
> 互いに矛盾することになります。

このとおりで矛盾であるとすれば、私が実装しようとしたこと自体が間違で、
実装方法を考えるまでもないということですね。

「メンバ変数の値」を子クラスでしか知りえないとしても、
親クラスの実装ロジックで「メンバ変数」自身は呼び出せるのが、
抽象化だと思っていました。

結論なようなので、解決としておきます。
ありがとうございました。

キムラ
解決済み!

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