web-dev-qa-db-ja.com

関数が単一のアイテムまたは複数のアイテムをとることができる場合、複数の関数または配列をとる関数を1つだけ持つ方が良いでしょうか?

のようなものを考えてください...

(Pseudocode Javascript like)

var capitalizeWord: function(Word){
    Word.toAllCaps(); 
}

複数の単語を実行する必要があるが、まだ1つしか実行しない場合はどうなりますか。する方がいいですか...

var capitalizeWords: function(words){
    _.forEach(words, function(Word){
        capitalizeWord(Word);
    }
}

var capitalizeWord: function(Word){
    Word.toAllCaps(); 
}

または、1つの機能のみ

var capitalizeWords: function(words){
    _.forEach(words, function(Word){
        Word.toAllCaps();
    }
}

そして、私はちょうど1つのWordを大文字にする必要があるとき.... capitalizeWordsを呼び出す前にそれを配列にキャストしますか?

capitalizeWords([Word]);
2
Carson

2つの方法は有効なユースケースであるため、2つの方法を使用しても問題ありません。これの鍵は、あなたが示したように、一方のメソッドが他方を呼び出すようにすることです。コードを複製したくありません。

配列を操作する単一のメソッドを持つことも問題ありません。ただし、その方法を使用して1つのWordを頻繁に操作していることがわかった場合、最初のオプションの方が記述が簡単で読みやすくなります。

一部の言語(C#など)では、メソッドが無制限の数のパラメーターを(C#ではparamsキーワードを介して)指定できるため、言語がそのような機能をサポートしている場合は、それを使用してください。

7
mmathis

Betterは、アプリケーションのコンテキストでのみ定義できます。通常、選択するパブリックAPIは、アプリケーションのユースケースを反映する必要があります。

そのために、2つの異なるシナリオを示します。それぞれのシナリオで、異なる答えを示します。


シナリオ#1:単語の大文字化はユーザーストーリーです

テキスト編集アプリを開発していて、ユーザーが単語を選択して大文字にすることができるというユーザーストーリーがあります。

これは、capitalizeWordsがユーザーストーリーの一部であり、パブリックAPIの一部であることが理にかなっているシナリオです。その場合、私はそれを言うでしょう:

  • 1つのWordを選択することがNワード(N = 1)を選択する特別なケースである場合、これをリストを受け取る単なる関数として表すことができます。
  • ユーザーが1つのWordだけを編集できる特別なケースがあり、それが多くの単語の編集と意味的に異なる場合、それらを2つの異なる関数として表現することは、理にかなっています。

シナリオ#2:単語の大文字化は単なる実装の詳細です

Webアプリを開発していて、キーワード検索機能があります。検索で大文字と小文字を区別しないという要件の一部として、capitalizeWordを呼び出しています。

その場合、capitalizeWordは実装の詳細であり、その結果、パブリックAPIの一部ではありません。これは、パブリックAPI searchByKeywordsが機能している限り、どのストーリーを選択しても、ユーザーストーリーにとって重要ではないことを意味します。

複数の関数に分離することを選択する唯一の基準は、コードをよりクリーンにすることです。

私の意見では、2つのオプションはどちらもクリーンなコードです(capitalizeWordscapitalizeWordListに名前変更することを除いて、違いはより明白です)。


通常、単語を大文字にすることはユーザーストーリーではないので、シナリオ2で作業していると思います。

5
Albuquerque

問題のドメインと、最も一般的な使用例を検討してください。

時間の90%の場合、クライアントコードは配列またはその他のコレクション型で動作します。たとえば、キャッシュの局所性を促進するためにそのようにすることが望ましい場合は、配列のバージョンを用意することをお勧めします-それはクライアントコードの記述方法を提案します。

そうでない場合は、両方を用意します(最も一般的な使用例、パフォーマンス要件などの理解に基づいて、どのバージョンがどれを呼び出すかを決定します)。または、より理にかなっていると思われる場合は、単一アイテムのバージョンのみを使用してください。

次に、一般化された方法で利便性について考えるのではなく、より焦点を絞った方法でAPI設計に取り組みます。システムが実際にどのように使用されるのか、およびシステムにどのような制約があるのか​​を検討します。

1

これは実際のスタイルの質問には答えませんが、ES6では、rest/spread演算子を使用してコードを簡略化し、間違いなく明確にすることができることに注意してください。以下の最も単純なケースでは、呼び出し元は、関数を呼び出す前に配列を広げることを覚えておく必要があります。

function capitalize(...words) {
  return words.map((Word) => Word.toUpperCase())
}

console.dir(capitalize());                    // []
console.dir(capitalize("hi"));                // [ 'HI' ]
console.dir(capitalize("hi", "there"));       // [ 'HI', 'THERE' ]
console.dir(capitalize(...["hi", "there"]));  // [ 'HI', 'THERE' ]

拡散していない配列も受け入れることが重要な場合は、チェックを追加します

function capitalize(...words) {
   if (Array.isArray(words[0]))
     words = words[0];
   return words.map((Word) => Word.toUpperCase())
 }

console.dir(capitalize("hi"));                // [ 'HI' ]
console.dir(capitalize("hi", "there"));       // [ 'HI', 'THERE' ]
console.dir(capitalize(...["hi", "there"]));  // [ 'HI', 'THERE' ]
console.dir(capitalize(["hi", "there"]));     // [ 'HI', 'THERE' ]
console.dir(capitalize([]));                  // []

すべての場合において、関数は配列を返すことに注意してください。

0
user949300