Java のインターフェース内でクラスを定義する機能の実用的な側面は何でしょう:
interface IFoo
{
class Bar
{
void foobar ()
{
System.out.println("foobaring...");
}
}
}
Java のインターフェース内でクラスを定義する機能の実用的な側面は何でしょう:
interface IFoo
{
class Bar
{
void foobar ()
{
System.out.println("foobaring...");
}
}
}
Eric P によってリンクされたものとは別の使用法を考えることができます: インターフェイスのデフォルト/ノーオペレーション実装を定義します。
./アレックス
interface IEmployee
{
void workHard ();
void procrastinate ();
class DefaultEmployee implements IEmployee
{
void workHard () { procrastinate(); };
void procrastinate () {};
}
}
さらに別のサンプル — Null オブジェクト パターンの実装:
interface IFoo
{
void doFoo();
IFoo NULL_FOO = new NullFoo();
final class NullFoo implements IFoo
{
public void doFoo () {};
private NullFoo () {};
}
}
...
IFoo foo = IFoo.NULL_FOO;
...
bar.addFooListener (foo);
...
このページは、1つの例を非常によく説明していると思います。特定のタイプをインターフェースにしっかりとバインドするために使用します。
上記のリンクから恥知らずに切り取ったもの:
interface employee{
class Role{
public String rolename;
public int roleId;
}
Role getRole();
// other methods
}
上記のインターフェイスでは、Role タイプを従業員インターフェイス (employee.Role) に強くバインドしています。
私はそれをしたことがないことをためらうことなく言うことができます。あなたがそうする理由も思いつきません。クラス内にネストされたクラス? 確かに、そうする理由はたくさんあります。そのような場合、私はそれらの内部クラスを実装の詳細と見なす傾向があります。明らかに、インターフェースには実装の詳細はありません。
このイディオムが頻繁に使用される場所の 1 つは、XMLBeansです。このプロジェクトの目的は、XML スキーマを取得し、スキーマに対応する XML ドキュメントを双方向で使用できる一連の Java クラスを生成することです。そのため、XML を解析して xml Bean にしたり、xml Bean を作成して xml に出力したりできます。
一般に、ほとんどの xml スキーマ タイプは Java インターフェースにマップされます。そのインターフェイスには、デフォルトの実装でそのインターフェイスのインスタンスを生成するために使用される Factory があります。
public interface Foo extends XmlObject {
public boolean getBar();
public boolean isSetBar();
public void setBar(boolean bar);
public static final SchemaType type = ...
public static final class Factory {
public static Foo newInstance() {
return (Foo)XmlBeans.getContextTypeLoader().newInstance(Foo.type, null);
}
// other factory and parsing methods
}
}
私が最初にこれに遭遇したとき、このすべての実装ガンクをインターフェイス定義にバインドするのは間違っているように思えました。しかし、私は実際にそれが好きになりました。なぜなら、それはすべてをインターフェースに関して定義することができますが、インターフェースのインスタンスを取得するための統一された方法を持っているからです (別の外部ファクトリ/ビルダー クラスを持つのとは対照的に)。
これが理にかなっているクラス (特に、インターフェイス/実装を大幅に制御できるクラス) でそれを選択したところ、かなりクリーンであることがわかりました。
インターフェイス内のメソッドの戻り値の型またはパラメーターの型として使用されるクラスを定義できると思います。特に役に立たないようです。クラスを個別に定義することもできます。唯一の利点は、クラスが何らかの意味でインターフェイスに「属している」と宣言されることです。
Google Web Toolkit は、このようなクラスを使用して、「通常の」インターフェイスを非同期呼び出しインターフェイスにバインドします。
public interface LoginService extends RemoteService {
/**
* Utility/Convenience class.
* Use LoginService.App.getInstance() to access static instance of LoginServiceAsync
*/
class App {
public static synchronized LoginServiceAsync getInstance() {
...
}
}
}
インターフェイス内の静的クラスを使用すると、一般的なプログラミング フラグメントを短縮することができます。オブジェクトがインターフェイスのインスタンスであるかどうかを確認し、そうであれば、このインターフェイスのメソッドを呼び出します。この例を見てください:
public interface Printable {
void print();
public static class Caller {
public static void print(Object mightBePrintable) {
if (mightBePrintable instanceof Printable) {
((Printable) mightBePrintable).print();
}
}
}
}
これを行う代わりに:
void genericPrintMethod(Object obj) {
if (obj instanceof Printable) {
((Printable) obj).print();
}
}
あなたは書ける:
void genericPrintMethod(Object obj) {
Printable.Caller.print(obj);
}
プライベートではないネストされたクラスを作成するのが良い考えのように思われる場合は常に注意してください。ほとんどの場合、外部クラスに直行する方がよいでしょう。しかし、入れ子になったパブリック クラスを作成する場合は、それをクラスよりもインターフェイスに配置する方が奇妙に思えません。外側のクラスの抽象性は、ネストされたクラスの抽象性とは必ずしも関係ありません。
これを行うと、「悪い設計決定」があちこちに書かれているようです。