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()); 
    } 
} 

Я создал еще один класс для отображения информации, как правило, «S» в SOLID говорит, что класс не должен делать, который он не должен делать. И я думаю, что отображение этой информации не является ее задачей. (Пожалуйста, поправьте меня, если я ошибаюсь)

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(); 
} 

С помощью этого интерфейса IWeapon, я могу теперь в состоянии добавить много оружия, которые имеют weaponName и повреждения. Но если я хочу добавить еще одно оружие с добавленными функциями, мы должны следовать принципу 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(); 
    } 

Моя проблема заключается в том, как я впрыснуть IWeaponv1 к классу DisplayPerson выше? Возможно ли это, или мое понимание принципов SOLID просто неверно. Пожалуйста, поправьте меня, если вы увидите, что я сделал что-то неправильно или плохой практику :)

+0

Для этой структуры вы бы лучше использовать наследование, а не интерфейсы. Например. 'public abstract class Weapon {}' вместо 'IWeapon'. –

+0

Я думаю, что классы в вашем коде являются новыми, а не инъекционными. См. Эту статью для получения дополнительной информации: http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/ –

+0

Возможно, вы хотите преобразовать 'DisplayPerson' в« службу », называемую «PersonDisplayer», который берет оружие и человека (новые) как параметры метода, а не как зависимости. Взгляните на эту статью: https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99 –

ответ

1

Реализация, представленная вами в вопросе, выглядит хорошо с теоретической точки зрения; однако у него есть некоторые проблемы с дизайном в реальном мире.

  1. Хотя Single Ответственность Принцип делает способствовать более сплоченные классы, она не должна быть расширена до уровня, при котором каждая функциональность перемещается в новый класс. Речь идет о классе DisplayPerson, который не требуется вообще (или должен быть реализован по-разному, о чем я расскажу в ближайшее время). Классы представляют объекты реального мира.В реальном мире, если вы спросите у кого-то свое имя, они скажут вам свое имя, а не перенаправят вас другому человеку, который скажет вам свое имя. Таким образом, объект Person может иметь способ печати своих собственных свойств, и это никоим образом не противоречит принципу единой ответственности. То же самое касается и оружия.

  2. Считайте, что вы хотите напечатать range оружия, если оружие поддерживает эту функциональность/поведение. В соответствии с этим, DisplayPersonимеет-IWeapon ссылка, но IWeapon не имеет ranges как часть его договора. Как же вы печатаете range оружия? (range не будет доступен через iwep ссылка в методе DisplayAll). Вам нужно будет использовать проверку typeOf, а затем подавать IWeapon на номер IWeaponV1, чтобы вы могли вызвать метод ranges. Проблема с этим подходом заключается в том, что DisplayPerson теперь придется работать с двумя разными интерфейсами, а не работать с одним интерфейсом. (Не говоря уже о проверочные условия, которые бросают вызов цели использования общего интерфейса)

Keeping вышеуказанных пунктов в виду, вы можете сделать следующие изменения кода:

  1. Добавьте метод display к IWeapon интерфейс и Person класс.
  2. Распечатать свойства объекта в категории displayPerson класс. Точно так же, печатать Properites из оружия в display методом индивидуальной реализации оружия

С учетом указанных выше изменений, вы можете вызвать дисплей прямо на ваших Person или IWeapon объектов в DisplayPerson классе, опираясь на единый интерфейс (без нарушающего единой ответственности Принципа):

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

Здравствуйте, @CKing, вы говорите, что класс DisplayPerson бесполезен? Должен ли я удалить его? – Jhe

+0

Последнее, использует интерфейс для такого рода реализации, плохую идею, и я должен был использовать простое наследование (абстрактный класс), поскольку это новизны, не предназначенные для инъекций? Извините за слишком много вопросов.У вас есть разные аргументы, и я хотел бы знать, что принадлежит вам, поскольку я оценил ваш ответ. Заранее спасибо. – Jhe

+0

@ '' DisplayPerson' отлично, если вы внесете изменения, которые я предложил. Практически класс можно было бы назвать «PersonView», а не «DisplayPerson». В реальном мире «PersonView» будет отвечать за вызов соответствующей библиотеки графического интерфейса, чтобы привлечь человека вместе со своим оружием. * Newable * не имеет большого значения. Это может быть достигнуто с помощью интерфейсов путем удаления конструктора 'DisplayPerson' и передачи' Person' и 'IWeapon' вместо метода DisplayAll. Я не понимаю, почему абстрактные классы являются обязательными для этого. Принятый ответ неверен, как объяснялось в моем ответе. – CKing

0

Это иногда сбивает с толку, поскольку вы можете следовать принципу единой ответственности, так что все в порядке.

Есть пара проблем с кодом, который я хотел бы указать, прежде чем отвечать на ваши вопросы.

  1. WeaponName, Damage and Range - данные, они не являются функциональными. Они должны быть объявлены как собственность, а не как метод.
  2. Пистолет должен реализовать IWeaponv1. Который, я думаю, вы пропустили его по ошибке.
  3. Все свойства задаются в конструкторе, то есть. впрыск конструктора. Вам не нужен частный набор в этом случае для класса Person, или любые другие классы

Наконец, чтобы ваш фактический вопрос

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 

Это выглядит нормально, это не нарушает единый принцип ответственности. Вы просто задумываетесь над этим примером. В приведенном выше примере существует только один класс (Display person) с функциональностью, и остальные из них просто хранят данные. Это хорошо, когда вы отделяете данные от функциональности. Простой способ проверить, не нарушена ли единая ответственность, - это проверить имя метода на имя класса. Если это неуместно, вы нарушаете SRP.

+0

Я высоко оценил ваш ответ. Спасибо за исправление моих ошибок :) Но я думаю, что ваш пример выше «DisplayPerson disp1 ...» не будет работать, поскольку вы вводите «Gun class» в IWeapon. Это моя большая проблема. – Jhe

+0

Когда вы нажмете «Gun: IWeaponv1», ваша проблема исчезнет. В чем проблема? – CarbineCoder

+0

OMG! Вы гениальные люди. Извините, я отредактировал свою ошибку в StackOverflow, я думал, что я изменил свой код и в своем приложении. Еще раз извините. – Jhe

 Смежные вопросы

  • Нет связанных вопросов^_^