3

よりダイナミックにするために、デコレータパターンに代わるものを探しています。簡単な例として、次のコードがあるとします。

interface Resource {
    public String getName();
}

interface Wrapper extends Resource {
    public Resource getSource();
}

interface Readable extends Resource {
    public InputStream getInputStream();
}

interface Listable extends Resource {
    public List<Resource> getChildren();
}



class File implements Readable {
    ...
}

class Zip implements Listable, Wrapper {
    public Zip(Readable source) { ... }
}

ご覧のとおり、ZipはReadableを直接実装していませんが、読み取り元のリソースは実装しています。zipを作成するとします。

Zip zip = new Zip(new File());

すべての機能が相互に関連しているわけではないため、すべてのインターフェイスをスタックして相互に拡張したくない(たとえば、Listable extends Readable)ことも、すべてのオブジェクトを構築してすべての機能を実装することもできません。オブジェクトをラップすることで、その場でオブジェクトを「装飾」できるようにします。

これは一般的な問題だと思いますが、それを解決するためのパターンはありますか?「ラッパー」インターフェースを使用すると、もちろん、必要に応じてリソースのチェーンを調べて機能をチェックできますが、これが正しいアプローチであるかどうかはわかりません。

アップデート

問題は、上記のとおり、すべての機能が関連しているわけではないため、インターフェイスの適切な階層を構築できないことです。たとえば、次の任意の新機能があるとします。

interface Rateable extends Resource {
    public int getRating();
}

class DatabaseRateable implements Rateable, Wrapper {
    public DatabaseRateable(Resource resource) { ... }
}

実行する場合:

Resource resource = new DatabaseRateable(new Zip(new File));

結果として得られるリソースは、追加されたすべての機能(読み取り可能、一覧表示可能など)を「失いました」。評価可能拡張をリスト可能と言うのはばかげているでしょう。

もう一度、resource.getSource()を再帰的にチェックして、すべての機能を見つけることができました。即時の返信では明確な解決策がなかったので、おそらく再帰的なチェックは結局のところ良いオプションですか?

4

6 に答える 6

2

ここであなたが努力している概念はダックタイピングであるように私には聞こえますが、これはJava自体はネイティブには行いません(これについては、リフレクションベースのJavaライブラリに関する私のコメントを参照してください)。ただし、JVMで実行されている他の言語は確かにそうです。たとえば-groovy

class Duck {
    quack() { println "I am a Duck" }
}

class Frog {
    quack() { println "I am a Frog" }
}

quackers = [ new Duck(), new Frog() ]
for (q in quackers) {
    q.quack()
}

コードをgroovyで記述し、残りのJavaコードとシームレスに連携させて、groovyでこの問題を解決することができます。

于 2013-03-27T08:47:39.827 に答える
2

あなたが探しているのはミックスインだと思います

リンクされたウィキペディアのページには、それらをサポートするOOP言語の優れたリストがあります。それとも、Javaに特に関係していますか?

于 2013-03-27T08:49:51.597 に答える
0

オブジェクトを装飾するときは、通常、オブジェクトの1つのインターフェイスのみを装飾して、その動作の1つの側面のみを変更または追加します。オブジェクトの別のインターフェイスを別のデコレータで装飾できます。これらのデコレータは同時に存在できます。

1つのデコレータを1つのメソッドに渡し、もう1つを別のメソッドに渡すことができます。

これは、最初に複数のデコレータでオブジェクトをデコレートしてから、コードにオブジェクトを渡す場合にハッキーになります。

したがって、あなたの場合は、デコレータを1つのオブジェクトに再度ラップすることをお勧めします。これにより、リソースにどのような種類のデコレータが存在するかがわかります。

class Resource {
    private Readable readable; 
    private Listable listable;
    private Rateable rateable;

    setReadable(Readable readable) {
        this.readable = readable;
    }

    setListable(Listable listable) {
        this.listable = listable;
    }

    setRateable(Rateable rateable) {
        this.rateable = rateable;
    }

    public boolean isRateable(){
        return rateable != null;
    }

    public Rateable getRateable(){
        return rateable;
    }
    // etc
}

File file1 = new File();
Resource resource = new Resource(file1);
resource.setReadable(new ReadableFile(file1));
resource.setListable(new ListableFile(file1));
resource.setRateable(new DatabaseRateableFile(file1));

次に、リソースを渡すことができ、そのユーザーは、この特定のリソースが持つ機能を見つけることができます。

Qi4jフレームワークを使用すると、注釈を使用して、これ(およびそれ以上)をよりクリーンな方法で実行できます。フラグメントをコンポジットに構成します。ただし、慣れるまでには多少時間がかかります。リソースの独自の実装をロールすることの利点は、他の人に説明しやすくなることです。

于 2013-03-27T08:47:43.060 に答える
0

たぶん、アダプタパターンが役立つでしょう:

Readable r = zip.adapt( Readable.class );

これは、インターフェイスを実装adapt()するインスタンスを返すようにメソッドに要求します。zipReadable

実装では通常、登録されているすべてのタイプのラッパーを作成する方法を知っている「アダプターマネージャー」を使用します。

于 2013-03-27T08:50:20.703 に答える
0

ここではそれほど適切ではないかもしれませんが、動的な機能の発見:

public class Features {

    public <T> lookup(Class<T> intface) 
            throws UnsupportedOperationException {
        return lookup(intface, intface.getSimpleName());
    }

    public <T> lookup(Class<T> intface, String name) 
            throws UnsupportedOperationException {
        return map.get(...);
    }
}

public class X {
    public final Features FEATURES = new Features();
    ...
}

X x;
Readable r = x.FEATURES.lookup(Readable.class);
于 2013-03-27T08:55:20.340 に答える
0

私は(元の質問で提示されたように)私自身の提案を答えとして提供します。十分な数の人々がそれが価値のある解決策またはより良い解決策が来ないと考えるならば、私はそれを受け入れます。

要するに、私自身の解決策は、Wrapperインターフェースを使用してリソースをさかのぼり、どの機能が存在するかを把握することです。例を考えると:

Resource resource = new DatabaseRateable(new Zip(new File));

あなたはこれを行うことを想像することができます:

public Readable asReadable(Resource resource) {
    if (resource instanceof Readable)
        return (Readable) resource;
    else if (resource instanceof Wrapper)
        return (asReadable( ((Wrapper) resource).getSource() );
    else
        return null;
}
于 2013-03-27T10:02:44.833 に答える