web-dev-qa-db-ja.com

メソッドのオーバーロードはいつ適切ですか?

既存のかなり大きなシステムで作業しているとします。クラスmyObjectMyClassというオブジェクトがあります(例として、Javaで作業しているとします)。 myObjectは、Collection、たとえば、Listと、(私が思うに)無関係な他のオブジェクトを含むコンポジションです。含まれているListが公開されないようにするために、構成されているListのメソッドを呼び出すためのデリゲートメソッドが含まれています(用語が間違っていると申し訳ありません)。

このListが_List<String>_であるとしましょう。ただし、何らかの理由で、メインのアクセスメソッドはSomeOtherClassクラスのマスクメソッドです。新しい値のペアをListに挿入する場合、SomeOtherClassというsomeObjectのオブジェクトがあります。私はmyObject.insert(someObject)を呼び出し、insertメソッド内にStringを取得して_List<String>_に入れる魔法があります。

ここで、Stringの値のみを取得し、挿入するSomeOtherClassオブジェクトがないとします。 insertメソッドを変更できないと仮定すると、このシステムのすべてが壊れてしまいます。次に、insertメソッドをオーバーロードする必要がありますか?または、SomeOtherClassを呼び出すたびにinsertの新しいオブジェクトを作成する必要がありますか?

オーバーロードするとこんな感じになると思います...

_public void insert(String s) {
    ...
}

public void insert(SomeOtherObject obj) {
    this.insert(obj.magicStringMethod());
}
_

(この例は、昨日発生したオーバーロードに関する同様の(やや複雑な)状況に基づいた不自然なパズルです。不明な点がある場合は展開します)

これはメソッドをオーバーロードするのに適切な場所でしょうか?そうでない場合、メソッドをオーバーロードする必要があるのはいつですか?

10
blahman

さまざまなタイプをサポートする場合は、オーバーロードします。

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

または、さまざまなパラメーターリストを使用してプログレッシブインターフェイスをサポートするには:

public overload void MyOtherMethod()
{
    this.MyOtherMethod(DefaultValue);
}

public overload void MyOtherMethod(int value)
{
    this.MyOtherMethod(value, DefaultOtherValue);
}

public overload void MyOtherMethod(int value, bool otherValue)
{
    ...
}

少し頭がおかしくなり、異なるタイプとプログレッシブインターフェイスの両方をサポートすることもありますが、オーバーロードされたメソッド間で動作のバリエーションを作成しないようにする必要があることに注意してください。オーバーロードされた各メソッドは、オーバーロードされたグループ内の他のメソッドと機能的に同じである必要があります。そうでない場合、動作がどのように、いつ、なぜ変更されるのかが明確になりません。 2つの関数でまったく異なる処理を実行する場合は、それに応じた名前を付ける必要があります。

7
S.Robins

両方の方法が意味的に同等である場合、オーバーロードが適切であると思います。 dukeofgamingの例から盗むには:

これらは適切にオーバーロードされています:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a+b;
}

これらは:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a-b;
}

これは極端な例です(キャッチできなかった場合、最後のメソッドは実際に加算ではなく減算します)。ただし、同じ名前のクラスに複数のメソッドがある場合、それらは一貫して動作するはずです。

あなたの例では、与えられた情報から、それらは等価であるように見え(一方が他方を呼び出すため)、それらをオーバーロードすることは合理的だと思います。メソッドを追加する必要があるかどうかわからない場合でも、チームの上級者に質問しても問題はありませんが、追加した場合は同じ名前を使用します(つまり、オーバーロードします)。

7

基本的に、メソッドのパラメーターがメソッドの動作を決定するようにします。

簡単な例は次のとおりです。

_class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    //...
}
_

メソッドsum(a、b)に整数のカップルを渡すと、最初の実装を呼び出す必要があることがわかります。これは、メソッド呼び出しがメソッドシグネチャと一致するためです(つまり、ダブルsum(double、double)は、合計法2つの整数)。

呼び出しのシグネチャは利用可能な実装と一致している必要があるため、sum(string、string)を呼び出そうとしても、これがない限り機能しません。

_class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    public string sum(String a, String b){
        return "" + (Double.parseDouble(a) + Double.parseDouble(b));
    }
    //...
}
_

tl; dr:同じ名前のメソッドに与えるパラメーターに応じて、クラスが正しいメソッドを処理するようにします。

継承する場合は上書きと呼ばれます

この他のシナリオの良い例は、クラスを継承することでクラスのデフォルトの動作を変更する場合、特に template method パターン。メソッドに実装されたアルゴリズムの各ステップがあります。

_class Robot_とfireAtTarget(Target target)...と呼ばれるメソッドがあり、次々にfireWeaponA(target); fireWeaponB(target); fireWeaponC(target);を呼び出すとします。 Robotクラスのオブジェクトのみを追加できるrobot_armyというコレクションも必要です。ロボットはfireWeaponX()メソッドでデフォルトで機関銃を発射します。

次に、_class LazorRobot_と_class MissileRobot_を使用する必要があります。Robotをもう一度実装しますか?いいえ、LazorRobotとMissileRobotにRobotを継承させ、overloadfireWeaponX()メソッドでlazorzまたはミサイルを使用すると、残りのメソッドを再実装しなくても、さまざまな武器で同じ動作が得られます。

tl; dr:インターフェイスを壊すことなくメソッドの動作をクラスに依存させるには(robot_armyはRobotのみを受け入れますが、Robotを継承するすべてのクラスを受け入れます)。

5
dukeofgaming