3

これはJavaScriptの質問かもしれませんが、Node.jsでは、モジュールまたはメソッドが引数として「options」オブジェクトをとるのが一般的です。たとえば、私が話していることについては、Node.js APIドキュメントから取得した以下のhttp.request()メソッドを参照してください。

var options = {
  hostname: 'www.google.com',
  port: 80,
  path: '/upload',
  method: 'POST'
};

var req = http.request(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});

// write data to request body
req.write('data\n');
req.write('data\n');
req.end();

多くのプログラミング言語で私が目にする問題の1つは、どの値が何に対応すると思われるかを区別せずに引数が渡されることです。これは読みやすさを容易にするために使用される手法ですか、それとも私が見逃している根本的な概念がありますか?PHPなどの他の言語でこれと同じ手法を合理的に使用できますか?(もちろん、オブジェクトの代わりに連想配列を使用します)

4

4 に答える 4

11

あなたは確かに他の言語でこのテクニックを使うことができます。JavaScriptでの構造的な改善について具体的に話すことはできませんが、私の知る限り、このアイデアは入力パラメーターの数を減らすことです。

様式上の懸念(読みやすさ、サポート性、ソフトウェアが持つべきすべての優れた直感的なもの)として、ここで従う基本的な「ルール」は、多くのメソッド引数よりも少ないメソッド引数の方が優れているということです。これは、すべての引数が必要なわけではない場合に特に当てはまります。

静的に型付けされた言語、C#の例を考えてみましょう。

public Widget WidgetFactory(int widgetNumber, string widgetName, bool isActive, Widget parentWidget, List<Widget> childWidgets)
{
    // parentWidget may be null if there's no parent
    // childWidgets may be empty or null for no children
    // etc.
}

より複雑なオブジェクトの場合、これは非常に醜くなります。大量のオプションの(null許容)パラメーターを想像してみてください。(4.0より前の.NETでCOM相互運用機能を使用したことがある場合は、想像する必要はありません。)これらのパラメーターを必要とする複数の関数がある場合も想像してみてください。繰り返しますが、それは醜く速くなります。

したがって、使用するパターンは、すべてのオプションを別のオブジェクトにカプセル化することです。このオブジェクトの唯一の責任は、これらのオプションを維持することです。

public class WidgetCreationOptions
{
    public int WidgetNumber;
    public string WidgetName;
    // etc.
}

他の場所...

public Widget WidgetFactory(WidgetCreationOptions options)
{
    // etc.
}

オプションがより複雑になり、内部で相互に参照するロジックが含まれるようになると、オプションを独自のオブジェクトに抽象化することがますます理にかなっています。これは、少数の大きなオブジェクトではなく、多くの小さな単純なオブジェクトに向かって移動するための一般的なOOプラクティスです。

確かに、あなたはこの声明で絶対に正しいです:

多くのプログラミング言語で私が目にする問題の1つは、どの値が何に対応すると思われるかを区別せずに引数が渡されることです。

多くのメソッド引数を持つことになると、多くの「コードの臭い」があります。

  • あまりにも多くの引数。
  • 引数としてのブールフラグ(呼び出されているメソッドが複数のことを実行することを示す)
  • null許容引数(必要ない場合は、なぜ必要なのですか?)

現時点で私を逃れるものはおそらくもっとあるでしょう。しかし、あなたが決定したように、これは読むのが難しいです:

someObject.SomeFunction(1, false, null, "this is a string", false);

これははるかに明確ですが、はるかに明確です。

var options = {
    widgetNumber: 1,
    isActive: false,
    widgetName: "this is a string"
};

// ... elsewhere ...

someObject.SomeFunction(options);
于 2013-01-28T19:50:49.483 に答える
3

これはJavaScriptで非常に一般的なパターンであり、関数はより緩く結合される可能性があります。言うのははるかに簡単です:

doStuff( { someValue: 1, anotherValue: 2 } );

それよりも:

doStuff(1, null, null, null, 2);

前者の設計には2つの利点があります。

  1. 読みやすく、渡される値がより明確になります。null値を渡すのではなく、指定したくないパラメーターを省略できます。また、キーでラベル付けされているため、パラメーターが何であるかについてのヒントも得られます。
  2. 関数のシグネチャは変更でき、既存のコードを壊すことなく、キーを追加できます。を削除する可能性がありanotherValue、関数のシグネチャに空白のパラメータを保持するのではなく、そのキーを無視することができます。
于 2013-01-28T19:46:04.320 に答える
1

これにより、呼び出し元が引数の一部を渡す必要がなくなります。ポートのデフォルトが80で、メソッドのデフォルトが「POST」の場合、次のコードが必要になります。

http.request({
  hostname: 'www.google.com',
  path: '/upload',
}, callback)

すべての引数に切り替えると、リクエスト関数は次のパラメータを取ります

http.request(hostname, port, path, method, callback);

また、デフォルト値が必要な場合は、次のように呼び出す必要があります。

http.request(hostname, undefined, path, undefined, callback);

あなたが見ることができるものはあまりきれいに見えません。私は、このスタイルのパラメーターが文書化されていないことが多く、十分に文書化されていない場合、パラメーターの呼び出し方法を理解するのが難しくなる可能性があることに同意します

PHP、C#、Javaなどのクラスを提供する言語では、JavaScriptで匿名オブジェクトを表すクラスを作成できます。

PHPでは、配列を使用してJavaScriptの匿名オブジェクトを模倣することもできます。

于 2013-01-28T19:46:06.280 に答える
0

このパターンで私が見るいくつかの利点:

  1. 引数の順序を覚えておく必要はありません
  2. 一部(またはすべて)の引数をオプションにするのが簡単
  3. 関数本体自体の中で、引数を参照しているときは非常に明確です。たとえばoptions.user、の代わりにuser。これにより、渡された引数を誤って上書きすることがより困難になります。
于 2013-01-28T19:56:55.217 に答える