ここでポリモーフィズムは「異なるクラスから、同じ名前と手続きで呼び出される関数により、異なる処理を行う」という意味で使っています。
☆データベースを伴うソフトがクライアント都合でたびたび仕様変更になり(リリース後の改造を含む)、そのたびにテーブル名が変更になり秩序が失われ、DBのフィールドの整合と、API/GUI層のコード改造が積み上がり、関数内にコメントアウトされた過去の履歴が増え、月日が経って、ある日探しづらいバグ整合に苦しんだり、パフォーマンスが下がって「遅い!」とクレームが来たり、「こんな簡単な要望なのになんでこんな高い見積もりなんだ!ベンダーはユーザーの足元を見てるのか!」とクライアントから理不尽な(しかしこれまでクラス設計と命名規則の管理が甘かったことを後ろめたく感じるので、まずいなあとは思っていて、言い返せないような)お叱りを受けたりして、(じゃあどうすればいいんだよ...)と途方に暮れたことのあるプログラマやプロジェクトリーダーは必見です。
☆メリット:ポリモーフィングで記述されたコードは「書き換える必要がない」ということ。つまり、DB仕様が変わっても、GUIコード側の中身を理解して改変する必要がない(このありがたみは、DBシステムの改変に苦しんだ体験があり、GUIコードプログラマが既に退職して連絡が取れない、またはソースコードが複雑すぎて、理解するまでに悲惨なほどの工数を概算し、会社とクライアントの板挟みに嘆息したことのある人にはわかります)
InterSystems Cache'側の準備
基本クラスにBaseObject(InterSystemsではこれをスーパークラス、親クラスと呼ぶ)
BaseObjectの派生クラスにInhelitClass1, InhelitClass2(InterSystemsではこれをサブクラス、子クラスと呼ぶ)
を作成する(派生クラスの作り方は下記の過去記事に詳解しています)
https://qiita.com/torisan_/items/9d68d090c56ec4ddd8a5
Studioで作成するObjectScriptのコードは次の通り。記述したらビルド→コンパイルを忘れずに。
☆★☆ポリモーフィングとは、「継続したプロジェクトコードの中で、異なるクラスで同じ"名前規則"の関数で、同じ機能を実装していくこと」
つまり、ポリモーフィングの成否はプロジェクトマネージャーとクラス設計者の能力、努力が剥き出しになる箇所です。
☆★☆同じ機能は、プロジェクトの最初の段階から、モデリングを適切に行い、同じ名前を付けるように(そして外注に出すコードにも命名規則にこそ気を配るように)徹しましょう。
なお、Cache'では明示的な数字→文字列変換の関数はあまり存在しません(しかし、関数の戻り値が%Stringであるので、文字列型に変換されて出力されます。)
Class User.BaseObject Extends %Persistent
{
Property pid As %String;
Property name As %String;
Property age As %String;
Method fnct() As %String [ Language = cache ]
{
#dim s As %String
Set s = ..name
Quit s
}
Class User.InhelitClass1 Extends User.BaseObject
{
Property job1 As %String;
Method PolyFnct() As %String
{
Quit ..age * 0.8
}
}
Class User.InhelitClass2 Extends User.BaseObject
{
Property hobby1 As %String;
Method PolyFnct() As %String
{
Quit ..age * 0.5
}
}
VB.NET側の準備
VisualStudioでVisual Basicのフォームアプリケーションを選択し、ボタンを作成する。
プロジェクト→参照から、DotNetGatewaySS64.exeとInterSystems.Data.CacheClient.dllを追加する。(過去記事参照)
ObjectBindingを使ってBaseObject、InhelitedClass1、InhelitedClass2をObjectBinding.vbとしてエクスポートしてVB.NETのプロジェクトに取り込む。
VB.NETに、次のコードを入力する。ポリモーフィングを実現しているのはPolyFunc。引数がObject型であることに注目する。
Imports System
Imports InterSystems.Data.CacheClient
Imports InterSystems.Data.CacheTypes
Public Class Form1
Dim cnCache As CacheConnection
Private Sub CacheInitialize()
'接続の確立
Dim cacheConnectStr As String = "Server = localhost; Port=1972;" +
"Log File = C:\data\NewCarte.log; Namespace = USER;" +
"Password = yourpass; USER ID = yourname"
cnCache = New CacheConnection(cacheConnectStr)
End Sub
Private Sub Inst1()
CacheInitialize()
cnCache.Open()
Dim d As New User.InhelitClass1(cnCache)
d.age = 34
Dim s As String = PolyFunc(d)
MsgBox(d.ToString() + " " + s)
d.Save()
cnCache.Close()
End Sub
Private Sub Inst2()
CacheInitialize()
cnCache.Open()
Dim d As New User.InhelitClass2(cnCache)
d.age = 34
Dim s As String = PolyFunc(d)
MsgBox(d.ToString() + " " + s)
d.Save()
cnCache.Close()
End Sub
'Inst1,Inst2両方から呼ばれる(クラスによらない)関数(しかし、ポリモーフィングで適切な関数が呼び出される)
Private Function PolyFunc(o As Object) As String
Return o.PolyFnct()
End Function
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'User.InhelitClass1を利用する関数
Inst1()
'User.InhelitClass2を利用する関数
Inst2()
End Sub
End Class
コードを実行し、Button2をクリックして、次のようなMsgBoxが表示されることを確認する。VB.NET側からは、PolyFuncという共通関数だけが呼ばれ、処理が読み込まれたクラスによって変わることに注目します。