TL;DR

  • Clojure は Java のインタフェースをそのまま扱え、definterface で定義できる。
  • Java のクラスがサポートするインタフェースはクラス定義時に決まるので、File や Socket に新しいインタフェースを後から実装できない。これは Expression Problem の一種である。

内容

Clojure では Java のインタフェースをそのまま扱える。

メリットとデメリット

インタフェースには、次のメリットがある。

  • データ型は複数のインタフェースを実装できる
  • インタフェースは仕様だけを指定し、実装は提供しない。そのため、(多重継承で陥る)複数の実装をどう扱うかといった問題が生じない

デメリットは、既存のデータ型に新しいインタフェースを追加するには、そのデータ型を書き直す必要がある点である。

インタフェースの定義(definterface)

Clojure から Java のインタフェースを作るには、definterface を使う。

(definterface name & args)

たとえば、「入力元や出力先になれるもの」を抽象化するインタフェース IOFactory は、次のように定義できる。

(definterface IOFactory
	('java.io.BufferedReader make-reader [this])
	('java.io.BufferedWriter make-writer [this]))

このインタフェースを実装するクラスは、自身を引数とし、BufferedReader と BufferedWriter を返す make-reader と make-writer 関数を実装しなければならない。

Expression Problem

ただし、クラスがサポートするインタフェースは、クラス定義時に決まる。Java のクラスは一度定義されたら、書き直さない限り新しいインタフェースを追加できないので、File や Socket、URL に IOFactory を実装することは不可能である。

ファイル以外の入出力を扱うようにした make-reader や make-writer のように、インタフェースはクラス作者以外の第三者に対しては閉じている。これは、Expression Problem と呼ばれる問題の一種である。Clojure はこの問題を回避するアプローチを用意している(Programming Clojure, Third Edition 第7章 プロトコル)。

キーワード