メソッドはオーバーライドするのと同じように、
親クラスの「フィールド」をオーバーライドすることはできないのでしょうか。
目的は、抽象クラスでフィールド名を定義し、子供のクラスで、そのインスタンスを定義することです。
Code:
{define-class public abstract A
field public data:String = {uninitialized-value-for-type String}
}
{define-class public B {inherits A}
field public data:String = "B"
}
不可能だとすれば、上記の目的を満たす、よい実装方法はありますでしょうか。
getter や、option で定義するのがよいのでしょうか。
コンストラクタ内で変数を作成し、セットするのがよいのでしょうか。
クラスの振る舞いではなく、内部に保持している値をオーバーライドすると言うと、
物凄い違和感を感じるのですが…
>目的は、抽象クラスでフィールド名を定義し、子供のクラスで、そのインスタンスを定義することです。
こちらはなんとなくやりたい事が理解できるので、これを実現する方法ということでは、
こんなコードではどうでしょうか?
とりあえず、危険なuninitialized-value-for-type を使わず、継承先での初期化忘れは
警告してくれるかと思います。
Code:
{define-class public abstract A
field public data:String
{constructor public {default data:String}
set self.data = data
}
}
{define-class public B {inherits A}
{constructor public {default}
{construct-super.default "B"}
}
}
やはり、コンストラクタで定義するのがよいのですね。
配列など、ある程度大きなデータを子クラス側で定義したいと思ったとき、
コンストラクタに持たせることで、コンストラクタのコード量が多くなってしまい(当たり前ですが)
ソースが見づらくなってしまうような気がしてしまい、
field に定義を任せられないかと思ったしだいです。
私は、オブジェクト指向の設計を理解していない、ということなのでしょうね・・・。
ありがとうございました。
そのコード量が多くなってしまう悩みは非常に共感できます
基本的にC言語を使っているプロジェクトで一部C++を使った際に同じ様な話がでて
「オブジェクト指向やりすぎ!もっと簡潔にコードかけないものか」と議論になった覚えが・・・
そのときは安全性第一だったので、初期化忘れのケアレスミスを防ぐためコンストラクタ
を使うことになりましたが、用途によっては他によい方法があるかもしれません。
大量にフィールドを定義した場合にgetter/setterを追加/変更するだけでメンテが
大変になるので設計書の定義からスクリプトでクラスの雛形を自動生成し、それに
処理を追加したり、更新前のコードをマージしたりするプロジェクトも見たことがあります。
(こっちはJavaでした)
余談ですが、ご参考まで
dyoshidaさん
アドバイスありがとうございます。
自動生成や、ソースをマージするという方法もあるのですね。
修正しているクラスのファイルに、上書きされると困るので、
初期値の設定を行う役割を別のクラスに移管させるようなデザインがよさそうですね。
初期化忘れがないように、また、正しい初期値が入っているかをチェックするクラスを用意し、
そのクラスを継承することで、
子クラスは、初期値が設定済みであることを前提に実装する、という方法が考えられそうです。
ちなみに、private フィールドならいけるかな、と思いましたが
当然、駄目でした。
Code:
{define-class A
field private data:String = "a"
{method {popup}:void
{popup-message self.data}
}
}
{define-class B {inherits A}
field private data:String = "b"
}
{CommandButton
{on Action do
def b = {B}
|| ↓B.data ではなく、 A.dataが表示される
{b.popup}
}
}