web-dev-qa-db-ja.com

クラスコンストラクターにデータ(対動作)を挿入するとはどういう意味ですか、なぜそれが悪い習慣と見なされているのですか?

Remo Jansenの "Learning TypeScript"という本を読んでいます。 1つのセクションで、著者はModelクラスの作成方法を含む、非常に単純な概念実証MVCフレームワークの作成方法を説明し、次のように述べています。

モデルには、使用するWebサービスのURLを指定する必要があります。 ModelSettingsという名前のクラスデコレータを使用して、使用するサービスのURLを設定します。コンストラクターを介してサービスURLを挿入することもできますが、クラスコンストラクターを介して(動作ではなく)データを挿入することは悪い習慣と見なされます

その最後の文がわかりません。特に、「データを挿入する」とはどういう意味かわかりません。過度に単純化された例を使用したJavaScriptクラスのほとんどすべての導入では、データがそのパラメーターを介してコンストラクターに導入(「注入」)されているようです。例えば:

class Person {
  constructor(name) {
    this.name = name;
  }
}

私は確かにnameを動作ではなくデータと考えています。これは、この種の例にコンストラクターパラメーターとして普遍的に含まれており、これが悪い習慣であるという言及は決してありません。したがって、私は上記の引用にある「データ」または「注入」またはその他の何かが意味するものを誤解していると思います。

JavaScript/TypeScriptでデコレータをいつ、どこで、どのように使用するかについての説明を含めることができます。概念は私が求める理解と密接に関連していると私は強く疑っています。ただし、より重要なこととして、クラスコンストラクターを介してデータを挿入することの意味と、それが悪い理由をより一般的に理解したいと考えています。


上記の引用にさらにコンテキストを与えるために、これは状況です:Modelクラスが作成され、この例では、NASDAQ用とNYSE用の証券取引モデルを作成するために使用されます。各モデルには、生データを提供するWebサービスまたは静的データファイルのパスが必要です。この本では、コンストラクターパラメーターではなく、デコレーターをこの情報に使用する必要があると述べており、次のようになります。

@ModelSettings("./data/nasdaq.json")
class NasdaqModel extends Model implements IModel {
  constructor(metiator : IMediator) {
    super(metiator);
  }
...
}

単にコンストラクタのパラメータとしてではなく、デコレータを介してサービスURLを追加する必要がある理由を理解していませんでした。

constructor(metiator : IMediator, serviceUrl : string) {...
10
Andrew Willems

私は著者に疑いの恩恵を与えます。おそらくそれがTypeScriptのやり方ですが、それ以外の環境では、真剣に取るべきではない完全に根拠のない主張です。

頭の中で、コンストラクターを介したデータの受け渡しが適切なさまざまな状況を考えることができます。中立的なものもあれば、悪いところもありません。

特定のクラスが特定のデータに依存して有効な状態になり、適切に実行される場合、コンストラクターでそのデータを要求することは完全に理にかなっています。シリアルポートを表すクラスはポート名をとることができ、ファイルオブジェクトはファイル名を必要とすることがあり、描画キャンバスはその解像度を必要とすることができます。コンストラクタでデータを渡さない限り、オブジェクトが無効な状態になる可能性があります監視して確認する必要があります。それ以外の場合は、オブジェクトのインスタンス化時にのみチェックし、その後、大部分が機能することを想定できます。著者らは、その有益な状況を不可能にしていると主張している。

さらに、コンストラクターでのデータの受け渡しを禁止すると、ほぼすべての不変オブジェクトが不可能になります。不変オブジェクトには多くの状況でさまざまな利点があり、それらのすべては作成者のポリシーで破棄されます。

変更可能なオブジェクトが必要な場合でも、この悪い習慣はどうですか?

var blah = new Rectangle(x,y,width,height);

賛成:

var blah = new Rectangle();
blah.X = x;
blah.Y = y;
blah.Width = width;
blah.Height = height;

著者は本当に最初のことは悪い習慣であり、私は常にオプション2で行くべきだと思いますか?それはおかしな話だと思います。

そのため、私はこの本を持っていないので、持っていてもそれを読むことはないので、この時点で、そのステートメントとかなり一般的なステートメントをかなりの疑いを持って表示します。

5
whatsisname

推測するだけです。

私が「データではなく行動を注入する」ことを耳にした場合、私はこれを行う代わりに考えます:

(疑似コードの例では申し訳ありません):

class NoiseMaker{
  String noise;
  NoiseMaker(String noise){
     this.noise = noise;
  }
  void soNoise(){
    writeToOutput(noise)
  }
}

これをする:

interface Noise{
  String getAudibleNoise();
}

class PanicYell implements Noise{
   String getAudibleNoise(){
       return generateRandomYell();
   }
   .....
}



class WhiteNoise implements Noise{
   String getAudibleNoise(){
       return generateNoiseAtAllFrequences();
   }
   .....
}

class NoiseMaker{
  Noise noise;
  NoiseMaker(Noise noise){
     this.noise = noise;
  }
  void soNoise(){
    writeToOutput(noise.getAudibleNoise())
  }
}

このようにして、ノイズの動作を常に変更し、ランダムにして、1つの内部変数に依存させることができます...

それは「継承を優先する合成」というルールがすべてだと思います。それは素晴らしいルールだと私は言わなければなりません。

これは、「Person」オブジェクトに名前を「挿入」できないことを意味しません。その名前は純粋にビジネスデータであるためです。しかし、あなたが与える例では、URLは何かを生成するために必要なものですsomehowサービスを接続します。そのどういうわけかは動作です:URLを注入する場合、「動作」を構築するために必要な「データ」を注入するので、その場合は、外部で動作を作成し、それを準備することをお勧めしますused:代わりに、URLを挿入します。使用可能な接続または使用可能な接続ビルダーを挿入します。

0
eddieferetro

ここで議論されているのはどのようなモデルかという状況に依存すると思います。 Remoの本はありませんが、このモデルは一種のサービスモデルであり、リモートWebサービスからデータを取得する必要があると思います。その場合、Webサービスモデルであるため、必要なすべてのデータを引数としてWebサービスのメソッドに渡し、サービスをステートレスにすることをお勧めします。

ステートレスサービスにはいくつかの利点があります。たとえば、サービスが呼び出されたサービスの詳細を見つけるためにサービスを構築するときに、サービスメソッドの呼び出しを読み取る人は誰も検索する必要がありません。すべての詳細は、メソッド呼び出しで使用されている引数に表示されます(リモートURLを除く)。

0
YudhiWidyatama