shimapapa.io

.NET,VB,C#,AzureなどMS関連中心の技術ブログ

VB.NETでJavaの「列挙型クラス」を模倣して「区分オブジェクト」を作る

増田本、読了しました。
Amazonのレビュー見ると結構賛否両論のようですが、
オブジェクト指向設計ドメイン駆動設計の基礎固めとして最適では、と自分は感じました。

「CHAPTER2 場合分けのロジックを整理する > Javaの列挙型を使えばもっとかんたん」を読んで、
おお、JavaEnumの値ごとにコンストラクタを付与したりできるのか・・・便利・・・
と恥ずかしながら初めて知りました。

.NETでも似たようなことをできないなかな、と探したら以下のようなMS公式リファレンスがありました。

docs.microsoft.com

上記と増田本のサンプルコードを真似してVB.NETで書いてみたのが以下のコード
(YenをValueObject化するのは端折ってIntegerにしてます)

本体

Public Interface Fee
    Function yen() As Integer
    Function label() As String
End Interface

Public Class AdultFee
    Implements Fee

    Public Function yen() As Integer Implements Fee.yen
        Return 100
    End Function

    Public Function label() As String Implements Fee.label
        Return "大人"
    End Function
End Class

Public Class ChildFee
    Implements Fee

    Public Function yen() As Integer Implements Fee.yen
        Return 50
    End Function

    Public Function label() As String Implements Fee.label
        Return "子供"
    End Function
End Class

Public MustInherit Class Enumeration
    Public Shared Function valueOf(Of T)(typeName As String) As T
        Return CType(GetType(T).GetField(typeName, Reflection.BindingFlags.Public Or Reflection.BindingFlags.Static Or Reflection.BindingFlags.DeclaredOnly).GetValue(Nothing), T)
    End Function
End Class

Public Class FeeType
    Inherits Enumeration

    Public Shared Adult As New FeeType(New AdultFee)
    Public Shared Child As New FeeType(New ChildFee)

    Private ReadOnly fee As Fee

    Sub New(fee As Fee)
        Me.fee = fee
    End Sub

    Public Function yen() As Integer
        Return fee.yen
    End Function

    Public Function label() As String
        Return fee.label
    End Function

End Class

クライアント側

Module Module1

    Sub Main()

        Dim feeForAdult = feeFor("Adult")
        Dim feeForChild = feeFor("Child")

    End Sub

    Public Function feeFor(feeTypeName As String) As Integer
        Dim theFeeType = FeeType.valueOf(Of FeeType)(feeTypeName)
        Return theFeeType.yen
    End Function

End Module

実行してみましょう。

f:id:rikupapa-shima:20190927230703p:plain

値取れてますね。
良い感じですが、リフレクションで変数名を指定するのはちょっと怖いです。以上。