Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有两个不同接口的构造函数注入(单一责任和接口隔离)_C#_Design Patterns_Dependency Injection_Solid Principles_Single Responsibility Principle - Fatal编程技术网

C# 具有两个不同接口的构造函数注入(单一责任和接口隔离)

C# 具有两个不同接口的构造函数注入(单一责任和接口隔离),c#,design-patterns,dependency-injection,solid-principles,single-responsibility-principle,C#,Design Patterns,Dependency Injection,Solid Principles,Single Responsibility Principle,我正在学习坚实的原则。我现在正在使用依赖注入和接口隔离原则。我已经掌握了这两个方面的基本知识,但当我把它们结合起来时,我感到困惑。这是我的实现 class Person { public Person(string name, int age) { Name = name; Age = age; } public string Name { get; set; } public int Age { get; set; }

我正在学习坚实的原则。我现在正在使用依赖注入和接口隔离原则。我已经掌握了这两个方面的基本知识,但当我把它们结合起来时,我感到困惑。这是我的实现

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());
    }
}
我创建了另一个类,用于将信息显示为SOLID中的“S”规则,即一个类不应该做它不应该做的事情。我认为显示这些信息不是它的任务。(如果我错了,请纠正我)

有了这个界面,我现在可以添加很多有武器名称和伤害的武器。但是,如果我想增加另一种具有附加功能的武器,我们必须遵循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类?有可能吗?或者我对坚实原则的理解是错误的。如果你看到我做了错事或不好的练习,请纠正我:)

有时会与你可以遵循的单一责任原则相混淆,所以没关系

在回答您的问题之前,我想指出代码中的几个问题

  • 武器名称、伤害和射程是数据,不是功能。它们应该声明为属性,而不是方法
  • 枪应该执行IWeaponv1。我想你是误会了
  • 所有属性都在构造函数中设置,即构造函数注入。在这种情况下,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 
    

    这看起来不错,它没有违反单一责任原则。在这个简单的例子中,你想得太多了。在上面的示例中,只有一个具有功能的类(displayperson)存在,其余的只是保存数据。当您将数据与功能分离时,这是一件好事。检查单个责任是否被破坏的一种简单方法是,对照类的名称检查方法名称。如果它不合适,那么您违反了SRP

    从理论角度来看,您在问题中提出的实施方案看起来不错;然而,它在现实世界中确实存在一些设计问题

  • 虽然单一责任原则确实促进了更具凝聚力的类,但不应将其扩展到每个功能都转移到新类的级别。例如,
    DisplayPerson
    类根本不是必需的(或者应该以不同的方式实现,我将在稍后讨论)。类表示真实世界的对象。在现实世界中,如果你问一个人的名字,他们会告诉你他们的名字,而不是把你引向另一个告诉你他们名字的人。因此,允许
    Person
    对象具有打印其自身属性的方法,并且这不会以任何方式违反单一责任原则。武器也是如此

  • 如果武器支持此功能/行为,请考虑打印武器的
    范围
    。目前,
    DisplayPerson
    有一个
    IWeapon
    参考,但
    IWeapon
    没有
    范围
    作为其合同的一部分。那么如何打印武器的
    射程
    ?(
    DisplayAll
    方法中的
    iwep
    参考将无法访问
    range
    )。您必须使用
    typeOf
    检查,然后向下转换
    IWeapon
    IWeaponV1
    ,以便调用
    范围
    方法。这种方法的问题是,
    DisplayPerson
    现在必须使用两个不同的接口,而不是使用单个接口。(更不用说违背使用公共接口目的的条件检查了)

  • 记住以上几点,您可以进行以下代码更改:

  • display
    方法添加到
    IWeapon
    界面和
    Person
    类中
  • person
    类的
    display
    方法中打印人员的属性。同样,在单个武器实施的
    显示方法中打印武器的属性
  • 通过以上更改,您可以通过依赖单个界面(不违反单一责任原则)在
    DisplayPerson
    类中的
    Person
    IWeapon
    对象上直接调用display:


    对于这种结构,最好使用继承而不是接口。例如,
    公共抽象类{}
    而不是
    IWeapon
    。我认为您代码中的类是新的而不是可注入的。有关更多详细信息,请参阅本文:可能您希望将
    DisplayPerson
    转换为一个名为“PersonDisplayer”的“服务”,该服务将武器和人员(可更新项)作为方法参数,而不是依赖项。看看这篇文章:我非常感谢你的回答。谢谢你也纠正了我的错误:)但我认为你上面的例子“DisplayPerson disp1…”不起作用,因为你正在将“Gun class”注入IWeapon。这是我目前最大的问题。当你这么做的时候,你的问题就会消失。做那有什么问题?天哪!你们是天才。很抱歉,我在StackOverflow中编辑了我的错误,我还以为我在应用程序中也更改了代码。对不起,再说一遍。@CarbineCoder我不同意。该准则违反了单一责任原则,因为它过度使用和误用了该原则。详细解释请参见我的答案。您好@CKing,您是说DisplayPerson类是无用的吗?我应该删除它吗?最后,在这种实现中使用接口是一个坏主意吗?我应该使用简单继承(抽象类),因为它是不可更新的
    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 
    
    public void DisplayAll() {
            Console.WriteLine("Person " + pers.display() + "\n has weapon: " + iwep.display());
    }