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


10

私はレモヤンセンの「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) {...

依存関係注入についてグーグルでクイック検索を行うことをお勧めします。これは、この質問をする正しいフォーラムではありません。:)
toskv 2016年

1
私はあなたの反応を心に留めますが、私はグーグルを検索し、依存関係注入の議論に遭遇しました。「依存性注入」と「データ注入」は同じものを指しているのですか?さらに、「依存性注入」は「良いこと」(または少なくとも「代替物」)であるとの印象がありましたが、私が提供した引用での「データ注入」の議論は「悪いこと」のように見えます。

依存性注入とデータ注入は2つの異なるものです。1つ目は設計原則であり、2つ目は一種の攻撃です。より明確な検索用語が必要な場合は、「制御の逆転」を試してください。少し広めですが、より明確な絵を描くのにも役立ちます。
toskv 2016年

1
「データインジェクション」攻撃は、引用された本の著者が彼が「データインジェクション」と言ったときに話しているものとは非常に異なる動物だと私は信じています。これが、Googleでの検索に不満を感じている理由の1つです。たとえば、SOLIDの原則をよりよく理解する必要がある場合でも、「名前」をパラメーターとして「Person」コンストラクターに提供することが正常で問題ないが、「serviceUrl」をパラメーターとして「モデル」に提供することは理解できません。コンストラクタが不適切である、または「名前」/「人物」の例とどのように異なるか

7
レモは間違いだと思います。彼が何を言っても、パラメーターデータです。注入されるデータには常に型が あり、オブジェクト指向言語のすべての型には何らかの振る舞いがあります。
Robert Harvey

回答:


5

私は著者に疑いの利益を与えます。おそらくそれが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で行くべきですか?それはおかしな話だと思います。

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


議論いただきありがとうございます。特に四角形の例を挙げたとき、あなたは私に「正しいにおいがする」と言います。筆者は、クラスに必要なデータとクラスの各インスタンスに必要なデータを区別しているのではないかと思います。しかし、私は本が説明するプロジェクトが本当にそれを明らかにするのに十分な深さに入っているとは思いません。付記として、あなたの答えはオブジェクトの不変性の最初の調査について私に送りましたが、それは私の元の質問にどれほど関係しているか、または関係していません。
Andrew Willems 2016年

0

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

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


はい、モデルはデータを取得する必要があります(最終的にはリモートWebサービスから提案されますが、本ではこれは単なるデモなので、最初はインラインで直接コード化された模擬データです)。「Webサービスのメソッドで」引数としてデータを渡すことについての提案を理解できません。データをパラメーターとして渡すこと(1)コンストラクターの場合と(2)デコレーターの場合の違いについて質問していました。あなたは3番目のオプション、つまりデータをWebサービスのメソッドのパラメータ/引数として渡すことを提案しているようです。私はあなたの要点を逃していますか?
Andrew Willems

0

推測するだけです。

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

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

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」オブジェクトに名前を「挿入」できないことを意味しません。その名前は純粋にビジネスデータであるためです。しかし、あなたは、Webサービスを提供することを例に、URLは、あなたが何かを生成する必要があるものです何とかサービスを接続しています。それはどういうわけか動作です:URLを注入する場合、「動作」を構築するために必要な「データ」を注入するので、その場合は外部で動作を作成して使用する準備をする方が良いです。代わりにURLを挿入します使用可能な接続または使用可能な接続ビルダー。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.