0

clone() メソッドを実装するクラスを必要とするインターフェイスを作成しています。これに対する私の素朴なアプローチは、次のようなものでした。

public interface ISolvableGame {
    function clone():ISolvableGame;
    //...
}

他の場所:

public class MyGame implements ISolvableGame {
    public function clone():MyGame {
        // ...
    }
}

MyGame.clone()ISolvableGame を実装するクラスのインスタンスを返すため、この種の署名は合法であると想定していましたが、これはインターフェイスの契約を満たしているように思えます。ただし、上記のようなコードMyGame.clone()は、インターフェイスで指定されたものとは異なるシグネチャを持つという事実を参照して、コンパイル エラーを生成します。

したがって、私の質問は、実装されたメソッドがインターフェイスのシグネチャと正確に一致する必要がある場合、クローン メソッドを必要とするインターフェイスを作成するにはどうすればよいかということです。明らかに、インターフェイスをより具体的にしても意味がありません。しかし、実装されたメソッドの具体性を低くすると (つまり、 return と入力MyGame.clone()した場合ISolvableGame)、そのクローン メソッドの他のユーザーは、何を取得しているのかわからなくなります。

clone メソッドの 2 つのバージョンが必要ですか? 1 つISolvableGameはインターフェイスを満たすように型付けされ、もう 1 つMyGameはクラス内で使用するために型付けされますか? または、より良いアプローチがありますか?


注:私は ActionScript3 (ECMA4 仕様を実装する Java に似た言語) で作業しています。AS3 はインターフェースの扱い方が独特ではないという前提で、これを言語に依存しないというタグを付けました。しかし、上記のサンプル コードが他の言語で機能する場合、問題はその言語に固有のものである可能性があります。


更新: 私の言語のコア ライブラリがこれにどのように対処しているかを調べてみることにしました。たとえばIEventDispatcher、メソッドを定義するインターフェイスがあるため、サブクラスdispatch():Eventディスパッチするクラスは実装できません。これは最終的に私の問題に似ています。EventIEventDispatcher

コア ライブラリは、実装目的で存在するクラスからそのようなクラスを継承させることで、これに対処します。したがって、コンパイル時の型の安全性が得られますが、継承によって引き起こされる問題を回避するために通常はインターフェイスを好むため、そもそもインターフェイスを使用するポイントがかなり希薄化するという犠牲が伴います。EventDispatcherIEventDispatcher

私の選択は次のとおりだと思います。

  • コア ライブラリが行うように、最終的に継承に依存する
  • Frederik が説明するように、名前の異なる 2 つのメソッドを実装します。
  • James が説明するように、コンパイル時の型の安全性を犠牲にする

回答:最終的に、インターフェイスでメソッドを指定するオプションを使用しました。cloneToSolvableつまり、インターフェイスは、インターフェイス タイプに複製するメソッドを指定し、実装クラスには、より具体的に型指定された複製メソッドに加えて、そのメソッドが必要です。持っているかもしれません。これは、オプションの中で最も不快ではないように思えました。

4

3 に答える 3

1

I have no experience with ActionScript, so this may or may not be a workable solution, but in C# I usually do like this:

public class MyGame : ISolvableGame {
    public MyGame clone(){
        // ...
    }

    ISolvableGame ISolvableGame.clone() {
        return this.clone();
    }
}

In other words, I make a "typed" clone method (that does not implement the inteface, since it differs on the return type). Then I make an explicit implementation of the interface method, that will call the typed clone method and return the result. This is a legal move, since MyGame can be cast to ISolvableGame.

于 2009-08-30T11:10:06.897 に答える
1

AS3 では、オーバーロード (戻り値の型またはパラメーターの型によって区別される同じ名前の複数の関数) のみを行うことはできません (サブクラスは基本クラスの実装を置き換えることができます)。

例えば

function foo():int {}
function foo():String {}
function foo(a:String):void {}

foo という名前の関数のオーバーロードです。これは ActionScript では実行できません。インターフェイスは、ある意味でインターフェイスを「継承」しているという点で、オーバーロードよりもオーバーライドに非常に近いものです。

// in your specific case you couldn't have these two functions
// defined within the same scope
public function clone():MyGame {}
public function clone():ISolvableGame {}

あなたがやろうとしているのは、2 つの概念を混ぜ合わせることです。オーバーライドしようとしているインターフェイスをオーバーロードしたい。Fredrik の投稿が示すように、オーバーロードをサポートする言語 (AS3 はその 1 つではありません) でさえ、両方を同時に実行できないことがよくあります。インターフェイスは、正確なシグネチャを持つ関数を持つことを強制clone():ISolvableGameし、追加でオーバーロードすることはできませんclone():MyGame

タイプ セーフを探している場合は、コンパイル時に取得できませんが、呼び出し元で戻り値の型を確認すると、実行時に取得できます。

例えば

// this will throw if clone does not return an
// object that is cast-able to MyGame
var game:MyGame = MyGame(someObj.clone());

私も契約を強制できることを望んでいますMyGameが、その方法を知る方法はありません.

于 2009-08-30T18:01:24.130 に答える
0

継承されたクローン メソッドは、戻り値の型として常にスーパー クラスを持ちます。たとえば、すべてのイベント クラスflash.events.Eventは、オブジェクトを返すクラスの clone メソッドをオーバーライドし、Eventそれを実装して、それぞれの派生クラス オブジェクトを返します。

于 2009-09-01T07:20:36.473 に答える