犬ぶよツールズ制作記録

Javaによる研究生活のためのパッケージ、犬ぶよツールズ。
その開発と保守のための備忘録

名前と引数が同じだが無関係なメソッドのオーバーライド

2013-05-26 12:01:04 | Weblog

● 概要

JDK 1.5以降で導入された共変戻り値型によって、名前と引数が同じだが無関係なメソッドのオーバーライドが可能になっている。

 

● 状況

共変戻り値型が使える場合、図のようなオーバーライドが可能である。

前提は

+ あるインターフェイス(図ではInterfaceX)が、自身を戻り値型とするメソッド(図ではmethod(...): InterfaceX)を持つ。

+ あるインターフェイスないしクラス(図ではSuperclassA)が、自身を戻り値型とするメソッド(図ではmethod(...): SuperclassA)を持つ。

+ これらのメソッドmethod(...)は、名前と引数(その数と型と並び順)が一致する。
 
さらに、SuperclassAがInterfaceXを継承もしくは実装しているなら、SuperclassAを継承したクラスのメソッドmethod(...)は自動的に、InterfaceX#method(...): InterfaceXとSuperclassA#method(...):SuperclassAの両方をオーバーライドしたものになる。
 
一方、SuperclassAがInterfaceXを継承・実装しておらず無関係な場合、SuperclassAを継承したクラス(図ではClassB)がInterfaceXを実装しようとすると、2つのメソッドmethod(...)の戻り値型が整合せず、コンパイルできない。
 
この状況で、ClassBがメソッドmethod(...)を共変戻り値型によりmethod(...): ClassBとしてオーバーライドすれば、これはInterfaceX#method(...): InterfaceXとSuperclassA#method(...):SuperclassAの両方をオーバーライドしたものになる。
 
つまり、名前と引数が同じだが無関係なメソッドのオーバーライドが可能である。
 
 
※ この方法に名前はある?
※ この方法と関係するデザインパターンはある?
※ この方法を使って無関係な2つのメソッド(InterfaceX#method(...): InterfaceXとSuperclassA#method(...):SuperclassA)に共通の実装を与えるのが妥当な状況があるとして、これらの2つのメソッドに予め関係を与えておくことはできる?そこに意味はある?
 
 

GraphvizのDOTファイルを生成するライブラリ (jp.inubuyo.bone.graphvizパッケージ)

2013-05-02 17:41:32 | Weblog

● 概要

Graphvizはグラフ可視化のプログラムです。そのうち、dotプログラムは、DOT言語を解釈して有向グラフを描画します。

jp.inubuyo.bone.graphvizパッケージは、有向グラフの情報からDOT言語が書かれたテキストファイルを生成する簡便な方法を提供します。

 

● 基本方針

+ 有向グラフの情報を与えると、それに対応するDOTファイルを生成する機能を持った専用のクラスを作ります。これをGraphvizWriterとします。

+ 有向グラフの情報を様々なオブジェクトが提供できると便利です。そこで、必要な情報はインターフェイスを介してクラスGraphvizWriterとオブジェクトの間でやり取りします。このインターフェイスをGraphvizWritableとします。

+ ライブラリのユーザーは、GraphvizWritableを実装したオブジェクトを用意します。このオブジェクトをGraphvizWriterのメソッドに引数として渡します。これによってDOTファイルを生成します。

 

● クラスGraphvizWriter

DOTファイルを生成する機能を提供します。使い方の仕様は次のようにします。

+ クラスGraphvizWriterの各インスタンスを、生成されるDOTファイルに対応させます。そこで、コンストラクタで生成するDOTファイルのファイル名を受け取ります。

+ ユーザーは描画したいGraphvizWritableのオブジェクト1個について、メソッドwrite(GraphvizWritable): void を1回呼び出すことにします。

+ 全ての描画したいGraphvizWritableオブジェクトについてメソッドwrite()したら、最後にメソッドclose(): voidを呼び出します。これによって、DOTファイルが書きだされます。

 

これに対応して実装を次のようにします。

+ メソッドwrite()で受け取ったGraphvizWritableオブジェクトは、そのまま貯めておく。

+ メソッドclose()で、ファイルを生成し、全てのGraphvizWritableオブジェクトを書き出し、ファイルを閉じる。

+ GraphvizWritableオブジェクトが1個の場合はdigraphとして書き出し、複数ある場合はそれぞれをsubgraphとして書き出す。

+ 1個のGraphvizWritableオブジェクトを指定されたPrintWriterに書き出すpublicでstaticなメソッドprint(GraphvizWritable, PrintWriter)を提供する(※)。この実装はメソッドclose()による書き出しと同じメソッドによる。

 

● インターフェイスGraphvizWritable

現段階では、クラスGraphvizWriter最も単純な表示に対応します。

インターフェイスGraphvizWritableはそのために必要な情報を渡すメソッドを持ちます。

+ グラフ(もしくはサブグラフ)の名前 name(): String、ノードの数 numberOfNodes(): int、辺の数 numberOfEdges(): int

+ 有向グラフの情報は、getNodeName(intid): String、getEdgeStart(int id): String、getEdgeEnd(int id): String で渡します。これらの引数は、0以上でノード/辺の数未満の番号です。

+ セルには、形状・輪郭の色・内部の色を指定できます。DOTのshape, color, fillColorです。メソッドはgetNodeShape(int id): Stringなどです。

+ 辺には、スタイル・色を指定できます。DOTのstyle, colorです。メソッドはgetEdgeStyle(int id): Stringなどです。

 

● インターフェイスGraphvizWritableの実装

手軽に使えるインターフェイスGraphvizWritableの実装として、クラスGraphvizWritable_Simple、クラスGraphvizWritable_Listを

パッケージjp.inubuyo.bone.graphviz.implに置きます。

+ クラスGraphvizWritable_Simpleは、同じ書式のセルと同じ書式の辺から成るグラフ用です。グラフの形状を予め構成できる場合に使えます。

+ クラスGraphvizWritable_Listは、セルと辺のデフォルトの書式を指定でき、個別の書式も指定できます。セルと辺を随時追加してグラフを構成することができます。

 

(使用例)

Jythonによる使用例です。

>>> import jp.inubuyo.bone.graphviz as graphviz
>>> g = graphviz.impl.GraphvizWritable_List('neko')

>>> g.addNode('neko') 

>>> g.addNode('cat')
>>> g.addNode('gato')
>>> g.addEdge('neko', 'cat')
>>> g.addEdge('cat', 'gato')
>>>

これで3つのノード、2つの辺から成る有向グラフが出来ました。

>>> writer = graphviz.GraphvizWriter('nyan')
>>> writer.write(g)
>>> writer.close()
>>>

これでnyan.dotというファイルが生成されます。

中身は

digraph neko{
neko
cat
gato

neko -> cat;
cat -> gato;

}

このようになります。

これをdotコマンドで画像にすると

となります。

 

● まとめ

GraphvizWritableを実装し、あるいはGraphvizWritable_Listを利用して、有向グラフの情報を与えるだけで、DOT言語の詳細を気にすることなくJavaのプログラムから有向グラフを描画できます。