Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

継承とプロパティについて教えてください 解決済み

タグの編集...

投稿者 tamuLA   (社会人)   投稿日時 2022/5/9 22:13:09
下記のようなコードで

Public Class 社員
    Public Shared Property ID As Integer
End Class

Public Class AAA
    Inherits 社員
End Class

Public Class BBB
    Inherits 社員
End Class

 ・
 ・
 ・

AAA.IDに値を代入するとBBB.IDにも同じ値が代入されてしまいます。
値を別々に保持したいのですが、この場合どのようなコードに修正すればよろしいでしょうか。
色々試したのですが全てダメでした。

※継承がイマイチ解っておらず、的外れなコードになっているかもしれません。申し訳ございません。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/9 23:05:20
> AAA.IDに値を代入するとBBB.IDにも同じ値が代入されてしまいます。

Shared Property ID はシャドウイングされていないため、
AAA.ID や BBB.ID へのアクセスは、単に 社員.ID へのアクセスと同義です。

シャドウイングすれば別物となります。
Public Class AAA
    Inherits 社員
    Public Shared Shadows Property ID As Integer
End Class



実装を変更する方法としては、シャドウイングのほかにオーバーライドがありますが、
Shared はオーバーライドできない仕様です。(オーバーライドできるのはインスタンスメンバーのみ)


> 値を別々に保持したいのですが、この場合どのようなコードに修正すればよろしいでしょうか。
別々の値を保持したいのであれば、Shared ではなくインスタンスメンバーにすべきです。
インスタンスメンバーであれば、個別の値を持てますし、必要に応じてオーバーライドもできます。
複数のインスタンスが不要なら、Singleton な実装にしておけばよいわけで。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/9 23:08:16
無理矢理ですが、
Public Shared Property ID() As Integer
をベースクラスに用意したまま、継承先で異なる ID を保持させてみる。


Module Module1
    Public MustInherit Class 社員(Of T)
        Private Shared ReadOnly InternalIDs As New Dictionary(Of Type, Integer)()
        Public Shared Property ID() As Integer
            Get
                Dim currentID As Integer
                InternalIDs.TryGetValue(GetType(T), currentID)
                Return currentID
            End Get
            Set(ByVal newID As Integer)
                InternalIDs(GetType(T)) = newID
            End Set
        End Property
    End Class

    Public Class AAA
        Inherits 社員(Of AAA)
    End Class

    Public Class BBB
        Inherits 社員(Of BBB)
    End Class

    Sub Main()
        AAA.ID = 123
        BBB.ID = 456
        MsgBox(AAA.ID)
        MsgBox(BBB.ID)
    End Sub
End Module


投稿者 (削除されました)   ()   投稿日時 2022/5/9 23:08:17
(削除されました)

投稿者 (削除されました)   ()   投稿日時 2022/5/10 12:07:46
(削除されました)

投稿者 tamuLA   (社会人)   投稿日時 2022/5/10 12:15:32
仮面弁士さん、昔からお世話になりっぱなしで直接ご回答頂いたことに大変大変恐縮です。


>別々の値を保持したいのであれば、Shared ではなくインスタンスメンバーにすべきです。
となると、newで動的にインスタンス化して管理してくのが(浅い理解でなんか表現が変かも)
設計として自然な感じでしょうか。


あとシャドウイングというものを全く知りませんでした。ありがとうございます。
私がスレ立てしたようなコードの形でシャドウイングで書くと、

Public Class AAA
    Inherits 社員
    Public Shared Shadows Property ID As Integer
End Class

Public Class BBB
    Inherits 社員
    Public Shared Shadows Property ID As Integer
End Class







とPublic Shared Shadows Property ID As Integer を書きまくらないといけない感じで
設計としては不自然になるという感じでしょうか。

力不足でコードのほうまだ追えていないのですが、こちらもじっくり取り組んでみたいと思います。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/10 12:57:14
まず Shared は、その名の通り「共有」です。個別の値を持つには適しません。

また Shared は、継承先でオーバーロードができないので、
 ・既存の Shared メンバーをそのまま受け継ぐ(動作は変更できない)
 ・新しい Shared メンバーを追加する(継承元には影響しない)
 ・既存の Shared メンバーを見えなくし、同名のメンバーでシャドウイングする。
の 3 パターンとなります。

VB の仕組み上、Interface に Shared なメンバーを追加することもできません。
(C# の場合は 8.0 以降で、インターフェイスへの共有メンバーの追加が許可されましたが)


> newで動的にインスタンス化して管理してくの
シングルトンにしてプロパティで単一のインスタンスを返すようにしたり、
ファクトリーメソッドを作りこんだりして、New することを
呼び出し側に意識させない設計にしては如何ですか?

たとえば
 Dim s1 As String = My.Computer.Name
という処理は、
 Dim c As New My.MyComputer()
 Dim s2 As String = c.Name
とも書けますが、利用者側は通常、New せずに使うことできますよね。

> 設計としては不自然になるという感じでしょうか。
コード云々以前に、クラス設計が不自然というか、そもそもの『意図』が不明瞭ですね。

社員クラスは MustInherit なわけでもないのに、
それを継承した AAA 側は、何も追加改修されていませんから…。

投稿者 shu   (社会人)   投稿日時 2022/5/10 16:34:28
IDが社員を特定するものであれば
Sharedで定義すること自体がダメです。

AAA, BBBがどのようなものを想定しているか分かりませんが
AAA:佐藤さん
BBB:木村さん
のように想定しているのであれば継承をせず
社員クラスに情報を追加して
佐藤さん用の変数、木村さん用の変数を社員クラスをnewで作成するのが
通常です。

AAA:営業部
BBB:技術部
というような想定であれば
共通の情報は社員クラスに配置し
営業部固有の情報はAAAクラスに
技術部固有の情報はBBBクラスに配置するとよいです。
この想定でも社員毎にAAAまたはBBBBに対しnewをして情報を保存するのは変わりません。

投稿者 (削除されました)   ()   投稿日時 2022/5/11 23:47:16
(削除されました)

投稿者 (削除されました)   ()   投稿日時 2022/5/12 00:13:54
(削除されました)

投稿者 tamuLA   (社会人)   投稿日時 2022/5/12 00:17:49
仮面弁士様、shu様、丁寧にご回答頂いて重ねて恐縮です。
大体問題が解ってきました。

>そもそもの『意図』
ここに尽きると思うのですが、


最初、グローバル変数が並んでたのがどんどん増えてしまい
クラスにしたら解りやすいかなと思い下記のようなコードになりました。
(Sharedはアクセス修飾子を考えないようにしたいという安易な考えで入れてました)

Public Class AAA
    Public Shared Property ID As Integer
    Public Shared Property Name As String
End Class



そのままOOPを解ってない状態でコードが膨れていき、
数年開発を続けてたらこういう形でものすごい量に増長してしまいました。
 
Public Class AAA
    Public Shared Property ID As Integer
    Public Shared Property Name As String
    Public Shared Property Score As Integer
 ・
 ・
 ・
End Class

Public Class BBB(内容は同上)
Public Class CCC(内容は同上)
Public Class DDD(内容は同上)
Public Class EEE(内容は同上)
 ・
 ・
 ・

 

これを1発でなにか短縮できないかと考えあまり使ったことない継承で
コードが激減するのではと考えた結果、
スレ立てしたようなコードにしたら良いのかな?と思ってハマってたという顛末です。

Public Class 社員
    Public Shared Property ID As Integer
    Public Shared Property Name As String
    Public Shared Property Score As Integer
End Class

Public Class AAA
    Inherits 社員
End Class

Public Class BBB
    Inherits 社員
End Class

 ・
 ・
 ・



ご回答に関して正直まだ解っていないところが多いのですが、
ここ2日ぐらい集中的に勉強しておりまして、ご回答の記載が6割ぐらい解るようになりました。

解決方法は最初に提示されたこちら
>別々の値を保持したいのであれば、Shared ではなくインスタンスメンバーにすべきです。
につきるということが段々解ってきており、おそらくOOPに合うような設計とコードに
変えることが解決であるようです。

本日もご回答を繰り返し読み返して勉強しております。
このような感じの質問にお時間を使っていただきすみません。感謝しております。m(__)m
引き続き勉強する所存です。