これらのメソッドを含むインターフェースを想定します:
_Car find(long id);
List<Car> find(String model);
_
このように名前を変更した方がいいですか?
_Car findById(long id);
List findByModel(String model);
_
実際、このAPIを使用する開発者は、初期find()
メソッドの可能な引数を知るためにインターフェースを調べる必要はありません。
だから私の質問はより一般的です:読みやすさが低下するため、コードでオーバーロードされたメソッドを使用する利点は何ですか?
これは、あなたが影響を受けやすい他の多くの悪い読みやすさの慣行と比較して比較的マイナーな問題なので、メソッドの名前の付け方は主に好みの問題だと思います。
そうは言っても、あなたがそれについて何かをするつもりなら、私はこの習慣に従います:
過負荷の場合...
これらのメソッドはほぼ同じ契約に従いますが、単に異なる入力で動作します(個人の納税者番号、口座番号、または名前と誕生日で口座を検索できる電話オペレーターを想像してください)。これには同じタイプの出力を返すが含まれます。
...の場合は別の名前を使用してください
これらのメソッドは、実質的に異なる処理を行うか、または(ケースのように)異なる出力を返します。データベースにアクセスし、アクセスしない場合は、別の名前を使用することを検討してください。
さらに、返されるタイプが異なる場合は、動詞を変更して次のことを示します。
Car findById(long id);
List findAllByModel(String model);
いずれの場合も、別の名前を使用することをお勧めします。将来的には、List<Car> findByMake(String make)
とは対照的に、別のメソッド、たとえばList<Car> findByModel(String model)
を追加することができます。そのため、突然、find
のすべてを呼び出すと意味がなくなります。また、メソッドの名前からそれらの使用方法に関する詳細情報が得られれば、メソッドが誤って誤って使用される可能性も低くなります。
メソッドの名前を変更すると、オーバーロードされなくなります。それ自体、オーバーロードによってコードが読みにくくなるとは限りませんが、構文が明確でないと、実装が追跡しにくくなる可能性があります。
多くの言語では、パラメーターがオプションであり、オプションのパラメーターのデフォルトが暗示される機能へのインターフェースを提供する手段として、メソッドのオーバーロードを使用しています。これは、メソッド宣言でデフォルトのパラメーター構文をサポートしていない言語に特に当てはまります。
これを行う:
_void MyMethod(int param1, int param2 = 10)
{
...
}
_
これを行うことからあなたを救います:
_void MyMethod(int param1)
{
MyMethod(param1, Param2Default);
}
void MyMethod(int param1, int param2)
{
....
}
_
どちらがより読みやすいかについては、それは本当にあなた次第です。個人的には、特にパラメーターリストが少し長くなる場合は、2番目のオプションを好みますが、API全体で一貫している限り、それは本当に重要ではないと思います。
基本的に同じことを行う関数が必要な場合、およびパラメーターリストを同じにしたいが、戻り値の型が異なる場合に、オーバーロードが困難になります。ほとんどの言語では、同じ名前で戻り値の型が異なる2つのメソッドを区別する方法がわかりません。この時点で、ジェネリックスの使用、パラメーターインターフェイスの変更、またはメソッドの1つの名前を変更して戻り値の型の違いを示すことを検討する必要があります。このような状況に対処するための単純で明確な命名方式に妥協しない場合、読みやすさが大きな問題になる可能性があるのはここです。
オーバーロードされたメソッドの名前をGetSomething()
とGetSomethingEx()
にしても、特にメソッド間の違いが戻り値の型である場合は、メソッド間の違いについてはあまり説明されません。一方、GetSomethingAsInt()
とGetSomethingAsString()
は、メソッドの動作についてもう少し詳しく説明します。厳密にはオーバーロードではありませんが、2つのメソッドが同様のことを実行していることを示します。異なる値タイプを返します。メソッドに名前を付ける方法は他にもあることは知っていますが、要点を説明するために、これらの大まかな例を使用してください。
OPの例では、メソッドのパラメーターが異なるため、名前の変更は厳密には必要ありませんが、メソッドをより具体的に指定する方がわかりやすくなります。結局のところ、それは本当にユーザーに提示したいインターフェースのタイプにかかっています。オーバーロードしないかどうかの決定は、読みやすさに対するユーザー自身の認識だけに基づいて行われるべきではありません。メソッドのオーバーロードは、たとえば、APIインターフェースを簡素化し、開発者が覚えておく必要があるメソッドの数を減らすことができます。その一方で、インターフェースを難読化して、開発者がメソッドのドキュメントを読んでフォームを理解する必要があります。使用するメソッドの種類は異なりますが、同様の名前が付けられたメソッドが多数あるため、その目的に関してメソッド名を読み取っているだけであることがわかります。
メソッドが同じものを返し、同じコントラクトに従う限り、オーバーロードを優先します。オーバーロードにより、呼び出し元のコードがパラメーター型に不必要にコミットすることがなくなります。
呼び出し元の関数がパラメーターとして検索クエリを受け取り、find
の呼び出しの前または後に他の処理を実行するとします。
void tryToSellCars(String which) {
/* grab an airhorn, inflatable tube guy... */
List<Car> cars = find(which);
/* expound virtues of each car in detail... */
}
将来、何らかの理由でそのクエリのタイプを変更する場合(たとえば、単純なID文字列から、何らかの機能を備えたクエリオブジェクトに変更するなど)、関数のシグネチャを変更するだけで、呼び出し側の関数に変更を加えることができます。クラスで呼び出すメソッドの変更を心配せずに、新しいパラメーターの型を受け入れる。
void tryToSellCar(CarQuery which) {
/* grab airhorn, inflate tube guy... */
List<Car> cars = find(which)
/* expound virtues of each car in detail... */
}
findById
とfindByQueryObject
を別々に実装する場合、その変更を行うにはすべての呼び出しを追跡する必要があります。この例では、Wordを1つだけ変更して完了しました。