オプションのパラメーターまたはオーバーロードされたコンストラクター


28

を実装しDelegateCommandていますが、コンストラクターを実装しようとしていたときに、次の2つの設計の選択肢を思いつきました。

1:複数のオーバーロードされたコンストラクターを持つ

public DelegateCommand(Action<T> execute) : this(execute, null) { }

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
    this.execute = execute;
    this.canExecute = canExecute;
}

2:オプションのパラメーターを持つコンストラクターを1つだけ持つ

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
    this.execute = execute;
    this.canExecute = canExecute;
}

どちらを使用するかわからないのは、提案された2つの方法のいずれかにどのような利点/欠点があるかわからないからです。両方とも次のように呼び出すことができます:

var command = new DelegateCommand(this.myExecute);
var command2 = new DelegateCommand(this.myExecute, this.myCanExecute);

誰かが私を正しい方向に向けてフィードバックをお願いできますか?


4
キッスとヤグニ。疑問がある場合は、両方を実装してください。しばらくしてから、両方のコンストラクターへの参照の検索を行います。それらのうちの1つが外部で消費されなかったとしても、私は驚かないでしょう。またはわずかに消費されます。これは、コードの静的解析の実行を見つけるのが簡単なものです。
ライヴ

1
静的コンストラクター(などBitmap.FromFile)もオプションです
BlueRaja-ダニーPflughoeft


2
@Laiv何か不足していますか?それらは同じ方法で使用されるため、同じ署名を持ちます。参照を検索して、発信者がどちらを考えていたかを知ることはできません。OPがその2番目の引数さえ持っているべきかどうかについて言及しているように聞こえますが、それはOPが尋ねているものではありません(そして、彼らは時々両方を必要とすることを確実に知っているかもしれないので、彼らは尋ねます)。
キャット

2
@Voo Openedge | Progress 10.2Bのコンパイラーはそれらを無視します。私たちの非破壊的なメソッド変更戦略はほとんど殺されました。代わりに、同じ効果のためにオーバーロードを使用する必要がありました。
ブレット

回答:


24

デフォルト値よりも複数のコンストラクターの方が好きです。個人的には、2つのコンストラクターの例は好きではありません。異なる方法で実装する必要があります。

複数のコンストラクターを使用する理由は、他のコンストラクターがメインのコンストラクターにデフォルト値を提供できるのに対して、メインのコンストラクターはすべてのパラメーターがnullではないかどうか、およびそれらが有効かどうかをチェックできるからです。

ただし、例では、2次コンストラクターでもnullaをデフォルト値として渡し、1次コンストラクターもデフォルト値を認識している必要があるため、それらの間に違いはありません。すべきではないと思います。

これは、次のように実装すると、よりクリーンで、より適切に分離されることを意味します。

public DelegateCommand(Action<T> execute) : this(execute, _ => true) { }

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
    this.execute = execute ?? throw new ArgumentNullException(..);
    this.canExecute = canExecute ?? throw new ArgumentNullException(..);
}

_ => trueプライマリコンストラクターに渡されることに注意してください。このコンストラクターは、すべてのパラメーターのチェックも行ってnullおり、デフォルトを気にしません。


ただし、最も重要な点は拡張性です。将来コードを拡張する可能性がある場合、複数のコンストラクターの方が安全です。さらに必要なパラメータを追加し、オプションのパラメータを最後に追加する必要がある場合、現在のすべての実装を中断します。古いコンストラクタ[Obsolete]を作成して、すぐにコードを壊すことなく新しい実装に移行する時間を与えて、削除されることをユーザーに通知できます。


一方、あるシナリオでいくつかのパラメーターが必要で、別のシナリオではオプションのパラメーターが必要な場合は、単にパラメーターを見て適切なコンストラクターを選択するのではなく、ドキュメントを調べる必要があるため、オプションのパラメーターを多すぎると混乱させることにもなります。


12
一方、オプションのパラメーターが多すぎると混乱します...正直なところ、パラメーターが多すぎると(オプションであるかどうかに関係なく)混乱します。
アンディ

1
@DavidPacker私はあなたに同意しますが、いくつのパラメーターが多すぎるかは別の話だと思います
;

2
パラメーターを省略するコンストラクターと、パラメーターのデフォルトを持つコンストラクターには別の違いがあります。前者の場合、呼び出し元は明示的にパラメーターを渡すことを回避できますが、後者の場合、呼び出し元はできません-パラメーターを渡さないことはデフォルト値を渡すことと同じです。コンストラクターがこの区別をする必要がある場合、2つのコンストラクターが唯一の方法です。
ゲイリーマクギル

1
たとえば、文字列をフォーマットするクラスがあり、オプションでCultureInfoオブジェクトを使用して構築できるとします。私はCultureInfo、追加のパラメーターを介してパラメーターを提供できるAPIを好みますが、提供された場合提供すべきではないと主張しましたnull。そうnullすれば、偶発的な値が「なし」を意味すると誤解されることはありません。
ゲイリーマクギル

拡張性が実際にオプションのパラメーターに対する理由あるかどうかはわかりません。必要なパラメーターがあり、それらの数を変更するObsolete場合、オプションのパラメーターがあるかどうかに関係なく、問題を回避するには、新しいコンストラクターと古いコンストラクターを作成する必要があります。オプションのパラメータを使用するとObsolete、削除する場合にのみ必要です。
ヘロタール

17

コンストラクターで行うのは単純な割り当てだけであると考えると、単一のコンストラクターソリューションがあなたの場合により良い選択であるかもしれません。もう1つのコンストラクターは追加の機能を提供しません。2つのパラメーターを持つコンストラクターの設計から、2番目の引数を指定する必要がないことは明らかです。

複数のコンストラクターは、異なる型からオブジェクトを構築するときに意味があります。その場合、コンストラクタは入力パラメーターを処理し、構築中のクラスの正しい内部プロパティ表現にフォーマットするため、外部ファクトリーの代わりになります。しかし、それはあなたの場合には起こらないので、単一のコンストラクタで十分なはずです。


3

それぞれのアプローチが輝ける2つの異なるケースがあると思います。

まず、単純なコンストラクターがある場合(私の経験では通常そうです)、オプションの引数を使用することを検討します。

  1. それらは、書かなければならないコードを最小限にします(したがって、読まなければなりません)。
  2. ドキュメントを1か所にまとめて、繰り返さないようにすることができます(これは、古くなる可能性のある余分な領域を開くため、悪いことです)。
  3. オプションの引数が多数ある場合、コンストラクターの非常に複雑な組み合わせのセットを避けることができます。ヘック、2つのオプション引数(互いに関連しない)だけでも、別々のオーバーロードされたコンストラクタが必要な場合、4つのコンストラクタ(バージョンなし、バージョンあり、バージョンあり)が必要になります。これは明らかにうまくスケーリングしません。

Buuuut、コンストラクターのオプションの引数が物事を明らかに混乱させるだけの場合があります。明らかな例は、これらのオプションの引数が排他的である(つまり、一緒に使用できない)場合です。引数の実際に有効な組み合わせのみを許可するコンストラクターをオーバーロードすると、この制約のコンパイル時の実施が保証されます。そうは言っても、このケースに出くわすことも避けなければなりません(たとえば、各クラスが排他的な動作を行うベースから継承する複数のクラスがある場合)。


複数のオプションパラメータを使用した置換爆発に言及するための+1。
Jpsy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.