はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」。見た目は JavaScript はおおむね達成していますが、中身は Ruby ってのはなんかイマイチか。。。もう少し考えよう。
-
スクリプト言語 KINX(https://github.com/Kray-G/kinx)
- 宜しければ★をポチっと。
- (近況報告1)整数定数値を簡単に扱えるように
enum
をサポートした。 - (近況報告2)Markdown で仕様を書いたらそのままテスト実行できる仕組みを作った。
- 名付けて
SpecTest
。これもそのうち紹介したいな。 - 一応:https://github.com/Kray-G/kinx/tree/master/doc/spec
- 名付けて
今回はオブジェクト指向の主役、クラスとモジュールです。
クラスとモジュール
クラスはオブジェクト指向の中で最も重要な概念。一言で言えば、「データと操作のパッケージ」だ。オブジェクトの形を定義する設計図になる。その設計図に基づいて作られた個々の実体が「インスタンス」。一般的に「オブジェクト」と言えばインスタンスのことを指すが、オブジェクトと呼んだ場合はもう少し幅広い概念を指す。
オブジェクト指向基礎講座おしまい。
早速クラスです。
クラス
クラスはオブジェクトの形を定義する設計図。サンプルは以下。もちろん定義だけあっても何も動かない。工場に図面登録しても実際にオーダーが入って生産ラインでモノを作らなければ何も出来上がらないのと一緒。
class ClassName(a) {
var privateVar_;
private initialize() {
privateVar_ = a;
this.publicVar = 0;
}
/* private method */
private method1() { /* ... */ }
private method2() { /* ... */ }
/* public method */
public method3() { /* ... */ }
public method4() { /* ... */ }
}
そこでインスタンス化だ。new
演算子でインスタンス化する。もちろんコンストラクタに引数を渡すこともできる。サンプルは以下の通り。
var obj = new ClassName(100);
ちなみに、インスタンス化する際に initialize()
メソッドがあれば自動的に呼び出されるが、コンストラクタの引数は initialize()
メソッドの引数ではないことに注意。また、コンストラクタに渡す引数が無ければ、(a)
ごと削除できる。class ClassName {...}
といった感じで。
Protected は現在未サポート。どうやって実現しようか検討中。
今時オブジェクト指向は常識みたいな扱いかとは思うが、あえて書くなら小難しい話よりもビャーネ・ストラウストラップの言ってた「オブジェクト指向の本質はカプセル化とマルチ・インスタンス」というのを理解するのが早いと思う。C では static 関数でカプセル化はできるがマルチ・インスタンスはできない。構造体を使えばマルチ・インスタンスはできるがカプセル化はできない。だから C with classes を作った、って。
マルチ・インスタンスが分かればオブジェクト指向も分かったも同然だ。たぶん。
継承
継承は :
を使う。基底クラスのコンストラクタに引数を渡すこともできる。基底クラスのメソッドは super
経由で呼び出せる。継承は俗に言う is-A 関係というやつだ。
class BaseClass(a0) {
public method1() { /* ... */ }
}
class ClassName(a0, a1) : BaseClass(a1) {
public method1() { /* ... */ }
public method2() {
method1(); // This is calling ClassName class's method.
this.method1(); // This is also calling ClassName class's method.
@method1(); // Same as `this.method1();`
super.method1(); // This is calling BaseClass class's method.
}
}
ちなみに Kinx では this.
(this plus dot) を @
で代用できます。
instanceOf
instanceOf()
メソッドを使ってどのクラスのインスタンスかを確認できる。尚、基底クラスのインスタンスであっても true を返す。サンプルは以下。
class BaseClass {}
class ClassName : BaseClass {}
var x = new BaseClass();
var y = new ClassName();
System.println(x.instanceOf(BaseClass)); // 1
System.println(x.instanceOf(ClassName)); // 0
System.println(y.instanceOf(BaseClass)); // 1
System.println(y.instanceOf(ClassName)); // 1
モジュール
モジュールは機能の追加を行う。いわゆる多重継承による菱形継承の問題の解決に役立つ。概念的には継承とは別の観点で機能を分離し、あとから追加できるようにしたもの。
犬も服を着るのが当たり前の時代、服を着るというのは人間だけの専売特許ではないのです(人間という抽象概念に含まれている機能ではない)。そういうものは後から色んなオブジェクトに mixin
。もちろん、服を着るための基本機能が備わってないとダメ。
module Printable {
public print() {
System.print(@value);
}
public println() {
System.println(@value);
}
}
class Value(v) {
mixin Printable;
private initialize() {
@value = v;
}
}
var v = new Value(100);
v.println(); // 100
この場合、Printable
モジュールは、メンバーとして @value
でアクセスできる要素があるクラスであれば mixin
して print
および println
メンバー関数をアタッチできる。モジュール Printable
内の @
、すなわち this
は、ホストとなるクラスのインスタンスを表すことに注意。上記の場合、mixin
された Value
クラスのインスタンスが Printable
の中で参照される。尚、複数のクラスに mixin
されたとしてもちゃんと区別される。
おわりに
今回も駆け足感がすごいなー。いつものように以下の定型フォーマットを貼っておきます。
- 最初の動機は スクリプト言語 KINX(ご紹介) を参照してください(もし宜しければ**「
いいねLGTM」**ボタンをポチっと)。 - リポジトリは ここ(https://github.com/Kray-G/kinx) です。こちらももし宜しければ★をポチっと。