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


10

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

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たとえば、別のクラスの内容を知る責任がなくなると思います。

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

どう思いますか?

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


2
言語の組み込みのメソッドオーバーロードを使用してカプセル化を処理しているだけだと思います。良くも悪くもありません。あなたのコードを助けるか傷つけることができるただのツール。
bitsoflogic 2019

5
あなたの目標は隠すのであればLatLng、こののクライアントからのCameraクラス、あなたはおそらく望んでいないmoveCameraTo(LatLng)というpublic
bitsoflogic 2019

回答で与えられたアドバイスに加えて、これはYAGNIについて言及する良い場所のように感じます。あなたはそれを必要とするつもりはありません。良いユースケースになる前にAPIメソッドを定義しないでください。なぜなら、あなたはそれを必要としないからです。
Patrick Hughes

moveCameraToLocationand moveCameraTo/に問題はありませんmoveCameraToCoords。確かに、同じ名前のLocation / lat / longをすべて渡したくないでしょう。
Insidesin '22

回答:


9

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

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

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

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

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

検討してください:

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

これにより、緯度と経度LatLngの問題に対処できます。コストはLatLng周りの知識を広めることです。これは高価に思えるかもしれませんが、私の経験では、原始的な強迫観念に代わる好ましい方法です。これは、パラメーターオブジェクトの確立を回避することで、行き詰まってしまうからです。

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

moveCameraTo( location.ToLatLng() );

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


1
私にはそれほど悪くはないように見えます-それは本当に消費者にとって便利なだけです。これが10回チェーンされている場合、または消費者がこれらすべてのオプションを実際に必要としない場合は、コードのにおいがします。
mcknz

1
しかし、各関数で、doubleをLagLngに、またはLocationをLagLngに変換するためのすべてのロジックを配置する代替策は何ですか?
Tlaloc-ES

@ Tlaloc-ESの方がいいですか?
candied_orange

@ Tlaloc-ES「変換」は、プリミティブがドメインロジックにロードされているときに一度だけ実行する必要があります。DTOを逆シリアル化すると発生します。次に、すべてのドメインロジックがオブジェクトLatLngまたはLocationオブジェクトを渡します。2つの間の関係を表示しNew LatLng(Location)たりLocation.toLatLng()、一方から他方に移動する必要がある場合に表示したりできます。
bitsoflogic 2019

1
@ Tlaloc-ES関連資料:Martin FowlerによるFlagArgument。「もつれた実装」セクションをお読みください。
Marc.2377

8

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

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

void moveCameraTo(double latitude, double longitude)私は何の問題は、単に呼び出すなかっ見るように実際に、コードを簡素化していないmoveCameraTo(new LatLng(latitude, longitude));ことの場所に。この方法も原始的な執着のにおいがします。

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

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

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

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

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

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

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

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


理由はわかりませんが、競合する回答があるにもかかわらず、私はこの回答を応援しています。私はあなたがポイントをより良くすることができたと思います。私の唯一のフィードバックは、この問題を扱っているすべての人が.NETにいるわけではないことを覚えておくことです。+1
candied_orange

@candied_orangeそうです。OPの質問をよく見ると、C#よりもJavaのように見えます。
陶酔

moveCameraTo(new LatLng(latitude, longitude));はプロジェクトのどの場所でも使用に問題はないと思いますが、moveCametaTo(latLng)を直接使用する方が明確であると思います。JavaのFileのように、文字列のようにパスを渡したり、Pathクラスのようにしたりできます
Tlaloc-ES

1

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

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


1

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

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

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

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.