2

私はSOLID Principlesを学習しています。私は現在Dependency Injection and Interface Segregation Principlesに取り組んでいます。私はすでにこの2つの基本を持っていますが、それを組み合わせると混乱します。ここに私の実装では、私はSOLIDに「S」ルールなどの情報を表示するための別のクラスを作成した。..2つの異なるインタフェースを持つコンストラクタインジェクション(単一責任とインタフェース分離)

class Person 
{ 
    public Person(string name, int age) 
    { 
     Name = name; 
     Age = age; 
    } 

    public string Name { get; set; } 
    public int Age { get; set; } 
} 

class DisplayPerson 
{ 
    private readonly IWeapon iwep; 
    private readonly Person pers; 
    public DisplayPerson(IWeapon iwep, Person perss) 
    { 
     this.iwep = iwep; 
     this.pers = perss; 
    } 

    public void DisplayAll() 
    { 
     Console.WriteLine("Name: " + pers.Name + "\nAge: " + pers.Age + "\n" + "Weapon: " 
      + iwep.weaponName() + "\nDamage: " + iwep.damage().ToString()); 
    } 
} 

のは、クラスは、行うことになっていないされてやるべきではないと述べています。そして、私はその情報を表示することはその仕事ではないと思います。私は今できweaponNameや損傷を持っている多くの武器を追加することができ、このインターフェースIWeaponで

class Sword : IWeapon 
{ 
    private string weaponNames; 
    private int damages; 
    public Sword(string weaponName, int damage) 
    { 
     this.weaponNames = weaponName; 
     this.damages = damage; 
    } 

    public string weaponName(){ return this.weaponNames; } 

    public int damage(){ return this.damages; } 
} 

public interface IWeapon 
{ 
    string weaponName(); 
    int damage(); 
} 

(私が間違っているなら、私を修正してください)。しかし、機能を追加した別の武器を追加したい場合は、ISPの原則に従わなければなりません。だから私はこのインターフェイスとクラスを作成しました。

class Gun : IWeaponV1 
{ 
    private string weaponNames; 
    private int damages; 
    private int range; 

    public Gun(string weaponName, int damage, int range) 
    { 
     this.weaponNames = weaponName; 
     this.damages = damage; 
     this.range = range; 
    } 

    public string weaponName() { return this.weaponNames; } 
    public int damage(){ return this.damages; } 
    public int ranges() { return this.range; } 
} 

public interface IWeaponv1 : IWeapon 
{ 
    int range(); 
} 

そして、私はこのようにそれを実装..

static void Main(string[] args) 
    { 
     DisplayPerson disp = new DisplayPerson(new Sword("Samurai Sword", 100), new Person("Jheremy", 19)); 
     disp.DisplayAll(); 
     Console.ReadKey(); 
    } 

私の問題は、私は上記のDisplayPersonクラスにIWeaponv1を注入どうやっているのですか?それは可能か、ソリッド原則の私の理解は間違っていますか?私が間違っているか悪い練習をしたことが分かったら私を修正してください:)

+0

をあなたはインタフェースではなく、継承を使用したほうが良いでしょう。例えば。 'IWeapon'の代わりに' public abstract class Weapon {} 'を追加しました。 –

+0

あなたのコードのクラスは注射可能ではないnewablesだと思います。詳細については、この記事を参照してください。http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/ –

+0

「DisplayPerson」を「サービス」に変換したい場合があります"PersonDisplayer"は武器と人物(newables)をメソッドパラメータとして持ち、依存関係ではありません。この記事をご覧ください:https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99 –

答えて

1

あなたの質問に提示する実装は、理論的な観点から見えます。しかし、実世界ではいくつかの設計上の問題があります。

  1. 単一責任原則はより密接なクラスを促進しますが、すべての機能が新しいクラスに移動されるレベルに拡張してはなりません。場合によっては、クラスが必要ではありません(または、別の方法で実装する必要があります)。クラスは実世界のオブジェクトを表します。現実世界では、人に自分の名前を尋ねると、自分の名前を伝える別の人にあなたをリダイレクトするのではなく、自分の名前を教えてくれます。したがって、Personオブジェクトは、それ自身のプロパティを印刷するためのメソッドを持つことができますが、これはSingle Responsibility Principleに反しません。同じように武器のために行く。

  2. 武器がこの機能/動作をサポートしている場合は、武器のrangeを印刷することを検討してください。現時点では、DisplayPersonは、IWeaponの参照番号を持っていますが、IWeaponは、契約の一部としてrangesを持っていません。どのようにして武器のrangeを印刷しますか? (rangeは、DisplayAll方法のiwep参照によってアクセスできません)。 typeOfチェックを使用してIWeaponIWeaponV1にダウンキャストし、rangesメソッドを呼び出す必要があります。この方法の問題点は、DisplayPersonが単一のインターフェイスで作業するのではなく、2つの異なるインターフェイスで動作する必要があることです。 (共通のインターフェースを使用しての目的を無視する条件のチェックはもちろんのこと)

では、次のコードを変更することができ、心の中で上記の点を維持する:

  1. displayメソッドを追加します。 IWeaponインターフェイスとPersonクラスです。
  2. displayメソッドの人物のプロパティをPersonクラスとして出力します。同様に、上記の変更により

個々の武器実装のdisplay方法で武器のproperitesを印刷するには、(単一のインターフェイスに依存することによってDisplayPersonクラスであなたのPersonまたはIWeaponオブジェクトに直接表示を呼び出すことができますシングル責任の原則)に違反なし:この構造体の

public void DisplayAll() { 
     Console.WriteLine("Person " + pers.display() + "\n has weapon: " + iwep.display()); 
} 
+0

こんにちは@CKing、DisplayPersonクラスは役に立たないと言っていますか?私はそれを削除する必要がありますか? – Jhe

+0

最後に、実装のこの種のインターフェイスを使用して悪い考えと私は注入可能ではないnewablesされている単純な継承(抽象クラ​​ス)を使用している必要がありますか?あまりにも多くの質問を申し訳ありません。あなたの人はさまざまな議論をしています。私はあなたの答えを高く評価して、あなたのことを知りたいと思います。前もって感謝します。 – Jhe

+0

@私が提案した変更を行うと 'DisplayPerson'はうまくいきます。実際には、クラスは 'DisplayPerson'ではなく' PersonView'と呼ばれることがあります。現実の世界では、PersonViewは、関連するGUIライブラリを呼び出して武器と共に人を描く責任があります。 * Newable *は大したことではありません。 'DisplayPerson'コンストラクタを削除し、' Person'と 'IWeapon'を' DisplayAll'メソッドに渡す代わりに、インターフェイスを使用することで実現できます。なぜ抽象クラスがこれのために必要であるのかわかりません。私の答えで説明したように、受け入れられた答えは間違っています。 – CKing

0

これは時々、単元責任の原則に従うことができますが混乱しています。

ご質問にお答えする前に、私が指摘したいコードにいくつかの問題があります。

  1. WeaponName、DamageおよびRangeはデータですが、機能性はありません。メソッドとしてではなくプロパティとして宣言する必要があります。
  2. ガンはIWeaponv1を実装する必要があります。私はあなたが間違ってそれを逃したと思う。
  3. すべてのプロパティはコンストラクタで設定されます。コンストラクタインジェクションあなたはそれが単一責任の原則に違反しない、最後にあなたの実際の質問

    DisplayPerson disp = new DisplayPerson(new Sword("Samurai Sword", 100), new Person("Jheremy", 19)); 
    
    DisplayPerson disp1 = new DisplayPerson(new Gun("Shotgun Axe", 100,100), new Person("Matt", 22); 
    //Assuming you have implemented Gun:IWeaponv1 
    

    にこれは正常に見える

Personクラスのために、その場合の民間セット、または任意の他のクラスが必要いけません。あなたはこの簡単な例でそれを考えすぎています。上記の例では、機能を持つ1つのクラス(表示人物)のみが存在し、残りはデータを保持しています。これは、データを機能から分離するときには良いことです。 Single責任が壊れているかどうかを確認する簡単な方法は、クラスの名前に対してメソッド名をチェックすることです。あなたが不在なら、あなたはSRPに違反しています。

+0

私はあなたの答えをとても高く評価しました。私の間違いを訂正していただきありがとうございます:)しかし、私はIWeaponに "Gun class"を注入しているので、 "DisplayPerson disp1 ..."の上のあなたの例はうまくいかないでしょう。これまでのところ私の大きな問題です。 – Jhe

+0

'Gun:IWeaponv1'を実行すると、問題はなくなります。それをやっている問題は何ですか? – CarbineCoder

+0

OMG!あなたは天才です。申し訳ありませんが、私はStackOverflowで私の間違いを編集しました。私は自分のアプリケーションで自分のコードを変更したと思いました。またすみません。 – Jhe

関連する問題