2013年07月20日

Kuinで引数付きコンストラクタを華麗に作るテクニック

Kuin0.03が出ましたね。わたしもちょいちょい書いてます。

今回話すことはタイトルのまんまです。
Kuinに付属されていたpdf、クラスのことはざっくりとしか書いておらず、情報も少ないです。
そういうわけで、まあこの記事読んで、少しでも情報を増やして貰えたら万々歳です〜

まあ、アイディアの問題なので、そんなに大したことはやってないですが、どうぞー


はい、というわけでまずはサンプルコードから

func Main()
class human()
var name : []char
var age : int

*func Ctor()
do this.name :: "アノニマス"
do this.age :: -1
end func

func IEternal(name_in : []char) : human
do this.name :: name_in
do this.age :: 18 {えいえんにじゅうはっさいだょ。うふふふふ・・・}

return this
end func

func ICommon(name_in : []char,age_in : int) : human
do this.name :: name_in
do this.age :: age_in

return this
end func

func Call()
do Dbg@Log(this.name ~ "(" ~ ((this.age>0)?(this.age.ToStr(),"不詳")) ~ ")" ~ "さんを呼びました")
end func
end class

var a : human :: #human
var b : human :: (#human).IEternal("がお")
var c : human :: (#human).ICommon("くいなちゃん",6)

do a.Call() {アノニマス(不詳)さんを呼びました}
do b.Call() {がお(18)さんを呼びました}
do c.Call() {くいなちゃん(6)さんを呼びました}
end func


これは人間クラスを作り、名前と年齢を与えてごにょごにょする例です。
ここでのポイントは、ざっくりと3つ。

@引数なしコンストラクタは、 「*func Ctor()」と記述する
A引数ありコンストラクタは、「I○○()」と記述する。戻り値はクラス型で、thisを返すようにする。
B引数付きコンストラクタを呼び出すときは、インスタンス生成時にコンストラクタを呼び出す


です。
@に関しては、わりとてきとーーーにですが、一応Readme.pdfの方にも書いてあったので、知ってる方も読み飛ばした方もそもそも読んでない方もいると思いますが、

Kuin側で正式にサポートしているコンストラクタの呼び出し方は、CClassに記述されている、Ctorをオーバーライドすることで呼び出します。
で、Kuinで記述したclassは、継承を省略した場合には、裏で勝手にCClassを継承しているので、Kuinで記述されるclassは例外なくCtorを親クラスが持っていることになります。
また、オーバーライドの仕方は、varやfuncの前に「*」という記号をつければいいのです。
以上のことから、まとめると「*func Ctor()」になるんですねっ

しかし、このやり方にはちょっと問題があります。
親クラスが持つCtorは、引数を1つも受け取らないメソッドです。つまりは引数付きのコンストラクタは使えないのです


そこでどうするか?まあメソッドをコンストラクタっぽくすればいいのです。(ここからAに関してです)
しかし、普通に名前をつけてしまっては、他のメソッド名とかぶってしまいます。そこで

コンストラクタ(風メソッド)の先頭には、必ず「I」という文字をつける といった俺ルールを適用します。
こうすれば、他のメソッドと名前がかぶりにくくなり、安心してコンストラクタと判断がつきます。

もちろんこれは俺ルールなので、皆さん個人個人で好きに命名すればいいのですが、私が先頭に「I」をつけることを推奨する理由は以下のとおりです。

1.「I」と先頭つけることで、Initなんだな、これはとすぐに判断がつく
2.文字数が少ない。1文字付け足すだけというのは魅力的。
3.一般的にC#とかでインターフェースを示すものにIを使うが、Kuinにはインターフェースが存在しないので問題ない


まあ、これをどう思うかは皆さんにお任せします〜。なお、誰がなんと言おうと私はこれを使います(しろめ)


次にBに関してですが、これがわりと重要なテクニックです。
「#クラス名」と記述すれば、そのクラスのインスタンスが生成されます。そのインスタンスは、当然「I○○」といった類のメソッドを持っているので、その場で実行すれば、あたかも引数をもったコンストラクタかのような挙動をしてくれます。

それが、「(#クラス名).I○○(引数1,引数2,...)」という形になるのです。

ちなみに、Aでthisを返す理由ですが、インスタンス生成時にはそのクラスのインスタンスが帰りますが、「(#クラス名).I○○(引数1,引数2,...)」って書くと、それは単にメソッドを実行しただけなので、インスタンスが帰りません。なので、クラス型の変数に代入できなくなるので、それを防ぐ目的でthisを返すようにさせます。

以上のことを守れば、多分素敵なオブジェクト指向()が出来るんじゃないですかね〜ってことでさらばじゃー


(おまけ)
Q.外部から引数なしのコンストラクタを呼び出したいです〜。あと、全部を統一的な書き方にしたいです〜
A.以下のようにしましょう。IDefault、わりと気持ちいいです。

class A()
*func Ctor()
do this.IDefault()
end func

func IDefault() : A
{なんかの処理1}
return this
end func
func INantoka(hoge : int) : A
{なんかの処理2}
return this
end func
func IKantoka(hoge : int,poyo : bool) : A
{なんかの処理3}
return this
end func
end class
posted by がお at 23:46| Comment(0) | Kuin | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

×

この広告は1年以上新しい記事の投稿がないブログに表示されております。