web-dev-qa-db-ja.com

javaのメソッドのStringパラメータの代わりに渡す推奨値

attachDevice(Device device)というメソッドがあり、引数は1つだけです。 attachDevice(Device device、String deviceName)のように、このメソッドにもう1つのパラメーターをオーバーロードする状況がありました。

単一の引数付き

public void attachDevice(Device device)
{
    ..
    ..        
}

二重引数​​付き

public void attachDevice(Device device, String deviceName)
{
    ..
    device.setName(deviceName);
    genericDeviceMap.put(deviceName, device);
    ..
}

実際、私のチームリーダーから、これら2つのメソッドを1つのジェネリックコールにするように求められました。オーバーロードされたメソッドには、単一のメソッド(上記のように示されている)よりも2行追加されています。 deviceNameを渡す代わりに、空の文字列を渡すことができます。これは、オーバーロードされたメソッドの呼び出しが、単一引数の呼び出しよりもはるかに少ないためです。しかし、引数がnullになる場合は名前を設定しないので、null値を渡す場合はどれほど悪いことでしょう。このシナリオのベストプラクティスはどれですか。

どんな提案も大歓迎です。

注:私がここで述べた実際の問題は、

i)オーバーロードされたメソッドを、コードの重複を避けるために汎用的な1つのメソッドにマージしたかった

ii)コーディングのベストプラクティスを守るために、メソッドに渡す推奨値(空の文字列またはnull値)が必要です。

与えられた回答から、私は自分の問題の最善の解決策を得ました。リンクされた質問 この質問は重複していますnull値の処理に関する情報を提供しますが、私がメモで述べた最初のポイントはカバーしていません。また、NPEがときどきスローされることを認識しているため、パラメーターとしてnullを渡して悪いコードを記述していません。

ありがとう。

5
S.K. Venkat

nullを使用することはお勧めしません。デバッグが困難なNPEがさらに発生する可能性があるためです(また、本番用コードで発生する場合は高額になります)。

解決策1(オーバーロード方式)

deviceNameが指定されていない場合は、代わりにデフォルトの値を指定できます。このアプローチの最大の欠点は、genericDeviceMap.put(deviceName, device)の危険性です。これは、キーがデフォルト名であるエントリを暗黙のうちに上書きできるためです(そのため、以前のDeviceを追跡できなくなります)。

_public void attachDevice(Device device)
{
    attachDevice(device, "DefaultName");       
}

public void attachDevice(Device device, String deviceName)
{
    ..
    device.setName(deviceName);
    genericDeviceMap.put(deviceName, device);
    ..
}
_

解決策2(抽出方法)

現在のアーキテクチャでは、名前なしでgenericDeviceMapが呼び出されたときにattachDeviceにエントリを追加しても意味がないかもしれません。その場合、2つのattachDeviceの間の共通の動作のみをプライベートメソッドに抽出するのが良い方法です。私は個人的にこの2つの理由でこのアプローチを好まない:

  • 2つのattachDevice間の動作は同じではありません。一方には副作用(device.setName(deviceName))があり、もう一方には副作用がありません
  • 外部スコープからのオブジェクトを変更するために、しばしば微妙なバグにつながる副作用自体

コード:

_public void attachDevice(Device device)
{
    preAttachDevice();
    postAttachDevice();      
}

public void attachDevice(Device device, String deviceName)
{
    preAttachDevice();
    device.setName(deviceName);
    genericDeviceMap.put(deviceName, device);
    postAttachDevice();
}

private void preAttachDevice()
{
    ...
}

private void postAttachDevice()
{
    ...
}
_

解決策3(削除方法)

私のお気に入りですが、最も難しいです。これら2つの方法が本当に必要かどうかを自問してみてください。名前を付けて、または付けずにattachDeviceを呼び出すことができるのは本当に意味がありますか? attachDevicemustは名前で呼び出されると言えるでしょうか?

この場合、コードは1つのメソッドのみに簡略化されます。

_public void attachDevice(Device device, String deviceName)
{
    ..
    device.setName(deviceName);
    genericDeviceMap.put(deviceName, device);
    ..
}
_

または、一方で、本当にMap個のデバイスとデバイス名を維持し、デバイス名を設定する必要がありますか?そうでない場合は、2番目のメソッドを削除して、最初のメソッドのみを保持できます。

_public void attachDevice(Device device)
{
    ...
    ...     
}
_
9
Spotted

あなたのチームリーダーが悪いコードを作成するように求めていると私は主張します。名前を指定したくない場合に、名前パラメーターとして任意の値を渡す必要があるので、メソッドの使用を検討している開発者が混乱し、混乱を招きます。

代わりに、2つのメソッドを保持します(後者の名前をattachNamedDeviceのような名前に変更して、attachDeviceとは異なることを明確にするために、共通コードをプライベートメソッドに移動します:

public void attachDevice(Device device)
{
    preDeviceNameSetup(device);
    postDeviceNameSetup(device);        
}

public void attachNamedDevice(Device device, String deviceName)
{
    preDeviceNameSetup(device);
    device.setName(deviceName);
    genericDeviceMap.put(deviceName, device);
    postDeviceNameSetup(device);        
}

private void preDeviceNameSetup(Device device)
{
    ...
}

private void postDeviceNameSetup(Device device)
{
    ...
}

そうすることで、APIをクリーンに保ちながら、実装でのコードの重複を回避できます。

4
David Arno

私は次のようにします:

  1. 2番目のパラメーターとしてストリングを使用して、2番目の関数を削除します。
  2. device.setName(deviceName)を呼び出す前にattachDevice(device)を呼び出します。デバイスの名前を設定するのはattachDeviceメソッドの責任ではありません。
  3. 次のコードスニペットに示すように、attachDeviceメソッドを変更して、デバイスに名前がある場合はgenericDeviceMapにデバイスを追加します。

デバイスに名前がないときにgenericDeviceMapにもデバイスを追加する必要がある場合は、Deviceクラス自体のコンストラクターなどでデフォルトを設定することをお勧めします。 。

public void attachDevice(Device device)
{
    // ...
    if (device.getName())
    {
        genericDeviceMap.put(deviceName, device);
    }
    // ...
}

これにより、懸念が分離され、副作用のある機能から離れることができます。

1
Thijs Riezebeek