Mixin Script Function in JavaFX Part 2
前回、JavaFX の mixin という機能で Function のみでなく Script Function も mixin できることを紹介しました。 今回はその続きで それを有効に利用する方法を紹介したいと思います。
前回も少し書きましたが...
通常、mixin は Java の interface と同様に その振る舞いに重要な意味を持ちます。
例えば、JavaFX 標準 API の Resizable は 縦横のサイズが変更できるという振る舞いを持った mixin クラスです。
しかし、今回紹介する mixin クラスは それらとは異なり、全く振る舞いを持ちません。
これは AbstractCollection 等のようなサブクラスの実装を手助けする抽象クラスに似ています。
mixin は本来のクラスが持つべき継承関係を崩すことなく実装を追加できるという点で優れています
で 実際にサンプルとして こんな mixin クラスを作ってみました。
$.fx
public mixin class $ {} protected function $R(r: Reader) { _R { reader: r }; } protected class _R { public-init var reader: Reader; public function eachLine(f: function(String):Void) { var r = new BufferedReader(reader); try { var s: Object; while ((s = r.readLine()) != null) { f(s as String); } } finally { r.close(); } } }
これは 以前 BufferedReader in JavaFX で紹介したコードを mixin を使って改良したものです。
上記の mixin を使うと 以下のように より簡単に 入力ストリームを扱うことができるようになります。
たったこれだけのコードでファイルを読み込んで標準出力することができるのです。とっても便利じゃないでしょうか。
Main.fx
public class Main extends $ {} public function run() { var r = new FileReader("test.txt"); $R(r).eachLine(function(line) { println(line); }); }
ところで このコーディングスタイルですが、どこかで見たことありませんか?
まさに JavaScript のライブラリ Prototype.js ですね...
標準出力するだけではあまり JavaFX ぽくないので、もう一つ $.fx の _R クラスに 以下の Fnction を追加してみました。
public function readLine(f: function(String): Object): Object[] { var r = new BufferedReader(reader); var seq: Object[]; try { var s: Object; while ((s = r.readLine()) != null) { insert f(s as String) into seq; } } finally { r.close(); } return seq; }
これは、入力ストリームからデータを読み込んで 1行毎に 引数で指定した関数を実行して インスタンスを生成し シーケンスで返すというものです。
これはこんな感じで利用できます。
Main2.fx
public class Main2 extends $ {} public function run() { Stage { scene: Scene { content: VBox { content: $R(r).readLine(function(line: String) { Text { content: line } }) as Node[]; } } } }
たったこれだけのコードで入力ストリームから読み込んだ文字列を Window 上に出力できるなんて...
さすが JavaFX...
ちなみに Java では あらゆる入出力がストリームという概念で扱うことができます。
それが ファイルであろうがネットワークであろうが関係なく...
つまり、上記のコードは ローカルファイルに限らず、ネットワーク経由のデータでも何でも簡単に表示できてしまうのです。
やっぱりすごいよ Java & JavaFX...
このように よく使いそうなロジックをまとめていけば、JavaFX版 Prototype.js ができるかも...
もし、使ってみたい人がいそうなら、ライブラリ化してみようかな...
ちなみに この mixin のクラス名は $ という変な名称ですが...
この mixin は クラスとしての意味はあまりないので、最も短い名称で あえて意味のないことを表す $ と命名しました。
また、Function 名 や 内部クラス名は mixin 先のクラス (今回の場合 Main.fx) の 変数や Function 等とかぶらないように、こちらも少し特殊な名前にしてあります。(ただ単に Prototype.js をパクった訳ではないのです。一応意味が...)