2

だから、あなたがこれを持っているとしましょう:

if ([foo respondsToSelector:@selector(bar:)]) {
   [foo bar:abc];
} else {
   [qux mux:abc];
}

そして両方bar:mux:副作用があります。

プロトコル(インターフェース)に@optionalメンバーなどがないJavaにどのように移植しますか?

私は3つの方法を考えることができます:

  1. Cの方法:どのメソッドが実装され有効であるかを表すビットフィールドを返すメソッドをインターフェイスに追加します。
  2. COMの方法:すべてのメソッドが結果コードを返し、E_NOTIMPLをチェックするようにインターフェイスを変更します。戻り値にはparamsを使用します。
  3. (私が想像しているのは)Javaの方法です。各インターフェイスメソッドをUnsupportedOperationExceptionをスローするものとしてマークし、それらをキャッチして、実装されていないメソッドをチェックします。

他の説得力のある選択肢を見逃しましたか?このコードが頻繁に呼び出されないため、パフォーマンスを最適化する必要がないと仮定すると、強制可能であるため、3が最良の方法であると思います。代替案についての議論はありますか?

4

3 に答える 3

2

MonoTouchには、まさにあなたの問題に対する確立された解決策があります。Objective-C用に設計されたコードをオブジェクト指向VM言語でかなり快適に感じるようにすることです。

彼らは、必要なすべてのメソッドをとしてマークする基本クラスを持ち、abstractオプションのメソッドをマークしない(または、より正確にはvirtual、C#のようにマークするが、Javaはそれを必要としない)ことによってそれを解決します。これは、オプションのメソッドを許可しながら、必要なメソッドのコンパイル時の強制を中心に明示的に設計されています。

詳細:http ://docs.xamarin.com/index.php?title = ios / tutorials / Events%2C_Protocols_and_Delegates#Protocols_Deep_Dive

于 2012-07-18T23:45:01.313 に答える
1

いいえ、「Javaの方法」と表現するのは、実際には逆の方法です。RuntimeExceptionサブクラスはプログラミングエラーのシグナルであるため、プログラムの通常のフローでサブクラスをキャッチすることはできません。

より良い方法は、プロトコルをより小さな部分に分割することです。必要なすべてのメソッドは単一のインターフェースになり、オプションのメソッドは独自の小さなインターフェースになります。これで、でオブジェクトをテストしてinstanceof、オプションのインターフェイスとその暗黙のメソッドが実装されているかどうかを判断できます。

次に例を示します。

@protocol MyProtocol
@optional
    -(void)method1;
    -(void)method2;
@required
    -(void)method3;
    -(void)method4;
    -(void)method5;
@end

interface IMyProtocol {
    void method3();
    void method4();
    void method5();
}

interface IMyProtocolMethod1 {
    void method1();
}

interface IMyProtocolMethod2 {
    void method2();
}

class MyProtocolImplWithMethod2 implements IMyProtocol, IMyProtocolMethod2 {
    public void method2() {
    }
    public void method3() {
    }
    public void method4() {
    }
    public void method5() {
    }
}

次に、このチェックを書くことができます:

if (obj instanceof IMyProtocolMethod2) {
    ((IMyProtocolMethod2)obj).method2();
}
于 2012-07-18T16:25:34.233 に答える
1

率直に言って、Javaの方法は、そのような状況をまったく回避することです。通常、Javaプログラマーは、ポリモーフィズムを壊さないようにさらに努力します(そして、多くの確立されたパターンを使用します)。したがって、タイプをオンにすることは悪い習慣と見なされます。

最も簡単な解決策と@optionalの直接変換は、instanceofを使用し、必要なメソッドを拡張するインターフェイス内にオプションのメソッドを含めることです。

interface MyProtocol {
   void required1();
   void required2();
}

interface MyProtocolWithOptional extends MyProtocol {
   void optional1();
   void optional2();
}

その後:

public static void test(MyProtocol mp) {
   mp.required1();
   if (mp instanceof MyProtocolWithOptional) {
       ((MyProtocolWithOptional)mp).optional1();
   }
}

多くのインターフェースがあり、アプリケーションが実行時に拡張可能である場合は、機能パターン(http://java.dzone.com/print/4771)のようなソリューションを使用できます。このソリューションでは、各オブジェクトに使用可能なインターフェース( COMに少し似ていますが、COMとは少し異なります)。次のようなものから始めます。

interface ThingWithCapabilities<T> {
    T interfaceFor(Class<T> inteface)
}

ThingWithCapabilitiesは、他のすべてによって拡張された基本インターフェースです。そして、実行時にそれを使用します。

public static void test(ThingWithCapabilities mp) {
    if (mp.interfaceFor(MyProtocolWithOptions.class) != null) {
        mp.interfaceFor(MyProtocolWithOptions.class).optional1();
    }
}

良い点は、キャスティングがなくなったことです。より良い点は、MyProtocolWithOptionsインスタンスのライフサイクルをThingWithCapabilitiesのライフサイクルに結び付けないことです(たとえば、MyProtocolWithOptionsの単一のインスタンスを多くのThingWithCapabilitiesインスタンスに対応させることができます。一方、次の場合はこれを返すことができます。 MyProtocolWithOptionsを実装することがあります)。これをnullオブジェクトパターン(nullの代わりにMyProtocolWithOptions機能を持たない各ThingWithCapabilitiesによって返される、何もしないMyProtocolWithOptionsのstatlessインスタンスがある場合)と組み合わせると、さらに優れたコードを取得できます。

public static void test(ThingWithCapabilities mp) {
    mp.interfaceFor(MyProtocolWithOptions.class).optional1();
}

あなたが何か大きなものを書いているのでない限り、このアプローチはおそらく複雑です。それは面白いので、私はちょうどそれについて言及しました(そして私はいくつかのペットプロジェクトでそれをうまく使用しました)。

于 2012-07-18T16:53:07.313 に答える