web-dev-qa-db-ja.com

関数を呼び出すこの方法は悪い習慣ですか?

私は次のコードを持っています:

public void moveCameraTo(Location location){
    moveCameraTo(location.getLatitude(), location.getLongitude());
}

public void moveCameraTo(double latitude, double longitude){
    LatLng latLng = new LatLng(latitude, longitude);
    moveCameraTo(latLng);
}

public void moveCameraTo(LatLng latLng){
    GoogleMap googleMap =  getGoogleMap();
    cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, INITIAL_MAP_ZOOM_LEVEL);
    googleMap.moveCamera(cameraUpdate);
}

このようにすると、たとえば、別のクラスのLatLngが何であるかを知る責任がなくなると思います。

また、関数を呼び出す前にデータを準備する必要はありません。

どう思いますか?

このアプローチには名前がありますか?それは本当に悪い習慣ですか?

10
Tlaloc-ES

言語のメソッドオーバーロード機能を使用して、位置情報に対するメソッドの依存関係を解決する別の方法を呼び出し元に提供しています。次に、カメラを更新する残りの作業を解決するために別の方法に委任します。

ここでのコードのにおいは、メソッドを呼び出すメソッドのチェーンを拡張し続ける場合です。 Location取得メソッドは、latLng取得メソッドを呼び出すdouble取得メソッドを呼び出し、最終的にカメラの更新方法を知っているものを呼び出します。

長いチェーンは、最も弱いリンクと同じくらい強いだけです。チェーンの拡張ごとに、機能する必要のあるコードのフットプリントが増加します。

それぞれの方法が、提示された問題を解決するために可能な最短の経路をとる場合、それははるかに優れた設計です。それは、それぞれがカメラを更新する方法を知っている必要があるという意味ではありません。それぞれが、位置パラメーターの型を1つの統一された型に変換する必要があります。これは、この1つの型が提示されたときにカメラを更新する方法を知っているものに渡すことができます。

そうすれば、他のすべての半分を壊すことなく1つを削除できます。

検討してください:

public void moveCameraTo(Location location){
    moveCameraTo( new LatLng(location) );
}

これにより、緯度と経度のLatLngs問題が処理されます。コストは、LatLngに関する知識を広めることです。それは高価に思えるかもしれませんが、私の経験では、それは primitive obsession の好ましい代替手段です parameter object を確立することを回避することで、行き詰まります。

Locationはリファクタリング可能であるがLatLngはリファクタリング可能でない場合は、Locationにファクトリを追加してこれを解決することを検討してください。

moveCameraTo( location.ToLatLng() );

これはまた、原始的な執着をうまく回避します。

9
candied_orange

ソリューションに特に問題はありません。

しかし、私の個人的な好みは、それらの方法はそれほど有用ではないということでしょう。そして、それらが離れているオブジェクトのインターフェースを複雑にするだけです。

その場所でvoid moveCameraTo(double latitude, double longitude)を呼び出すだけで問題はないので、moveCameraTo(new LatLng(latitude, longitude));は実際にはコードを単純化しません。この方法も原始的な執着のにおいがします。

void moveCameraTo(Location location)は、Location.ToLatLng()メソッドを証明し、moveCameraTo(location.ToLatLng())を呼び出すことで、より適切に解決できます。

これがC#であり、そのようなメソッドが本当に必要な場合は、インスタンスメソッドではなく拡張メソッドとしてそれらを使用します。このメソッドを抽象化して単体テストを行うと、拡張メソッドの使用法が明らかになります。単純な変換で複数のオーバーロードを作成する代わりに、単一のメソッドを偽造する方がはるかに簡単です。

このようにすると、たとえば、別のクラスのLatLngを知る責任がなくなると思います。

これが問題になる理由はわかりません。コードがvoid moveCameraTo(LatLng latLng)を含むクラスを参照している限り、間接的にLatLngに依存しています。そのクラスが直接インスタンス化されることはありません。

また、関数を呼び出す前にデータを準備する必要はありません。

どういう意味かわかりません。新しいインスタンスを作成したり、クラスを別のインスタンスに変換したりすることを意味する場合は、問題ありません。

考えてみれば、.NET自体のAPI設計にも支えられていると感じています。歴史的に、多くの.NETクラスは、さまざまなパラメーターを持つ多数のオーバーロードを持ち、内部で単純な変換を行うというあなたのアプローチに従いました。しかし、それは拡張メソッドが存在する前でした。最新の.NETクラスは独自のAPIでより軽量であり、パラメーターオーバーロードを持つメソッドがある場合、それらは拡張メソッドとして提供されます。古い例は NLog ILogger で、ログへの書き込みのために何十ものオーバーロードがあります。それを新しい Microsoft.Extensions.Logging.ILogger と比較します。これには合計3つのメソッドがあります(ロギング自体をカウントする場合は1つだけです)。しかし、 拡張メソッド のように、多くのヘルパーとさまざまなパラメータ化があります。

この答えは、いくつかの言語がこのようなデザインをより良くするためのツールを持っていることを示していると思います。私はJavaをあまり知らないので、同等のものがあるかどうかはわかりません。ただし、単純な静的メソッドを使用することもできます。

8
Euphoric

これの適切な名前が何であるかはわかりませんが、適切な方法です。複数のオーバーロードを公開し、呼び出しクラスが使用するパラメーターセットを決定できるようにします。あなたが言うように、別のクラスはLatLngオブジェクトが何であるかを知らないかもしれませんが、そのLocationを知っているかもしれません。

これらのメソッド間でコードを複製したくないので、一方のメソッドが他方を呼び出すことも重要です。完了したら、1つのメソッドを選択して作業を実行し、他のメソッドにそれを(直接または間接的に)呼び出します。

1
mmathis

ある種のメソッドを使用することを気にしているのであれば、それは単なるメソッドオーバーロード機能であり、優れています。

しかし、LatLngが何であるかを知る責任を排除するはありません。 LatLng latLng = new LatLng(latitude, longitude)を初期化しているからです。これは完全にLatLngへの依存関係です。 (初期化が依存関係の問題である理由を理解するには、Dependency Injectionを確認できます)オーバーロードされたメソッドを作成すると、LatLngを気にしないクライアントに役立ちます。もしそうなら、それもいいのですが、アプローチだとは思いません。これは、クライアントのための多くのサービス方法です。

したがって、アーキテクチャを設計するには2つのオプションがあります。

  1. 多くのオーバーロードメソッドを作成し、クライアントに提供します。
  2. インターフェースまたは具象クラスとしてパラメーターを必要とするオーバーロードメソッドをいくつか作成します。

パラメータとしてプリミティブ型を必要とするメソッドを作成することからできるだけ逃げます(オプション1)。ビジネスが何度も変化し、メソッドパラメータを再生する必要がある場合、すべての呼び出し元関数を変更して実装することは本当に難しいためです。

これの代わりに、interfaces(Dependency Injection)を使用します。コストがかかり、時間がかかると思われる場合は、クラスを使用して、それらのマッパー拡張メソッドを提供します(オプション2)。

1
Engineert