我正在学习SOLID原则。我现在正在使用依赖注入和接口隔离原则。我已经掌握了这两个的基础知识但是当我把它结合起来时,我感到很困惑。这是我的实施..
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”规则表示类不应该执行它不应该执行的操作。我认为显示这些信息不是它的任务。 (如果我错了,请纠正我)
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,我现在可以添加许多具有武器名称和伤害的武器。但是,如果我想添加另一种具有附加功能的武器,我们必须遵循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?是否有可能或我对SOLID原则的理解是错误的。如果你发现我做错了什么或做错了,请纠正我。)
答案 0 :(得分:1)
从理论的角度来看,你在问题中提出的实现看起来很好;但是,它确实在现实世界中存在一些设计问题。
虽然单一责任原则确实促进了更具凝聚力的类,但不应将其扩展到将每个功能移动到新类的级别。一个典型的例子是DisplayPerson
类,它根本不需要(或者应该以不同的方式实现,我将在稍后讨论)。类表示真实世界的对象。在现实世界中,如果你问一个人他们的名字,他们会告诉你他们的名字,而不是把你改名给另一个告诉你他们名字的人。因此,允许Person
对象具有打印其自身属性的方法,这不会以任何方式违反单一责任原则。武器也是如此。
如果武器支持此功能/行为,请考虑打印range
武器。目前,DisplayPerson
有一个 IWeapon
引用,但IWeapon
没有ranges
作为其合同的一部分。那怎么打印range
武器? (range
方法中的iwep
引用无法访问DisplayAll
。您必须使用typeOf
检查,然后向下转发IWeapon
至IWeaponV1
,以便您可以调用ranges
方法。这种方法的问题是DisplayPerson
现在必须使用两个不同的接口,而不是使用单个接口。 (更不用说违反使用通用接口目的的条件检查)
记住以上几点,您可以进行以下代码更改:
display
方法添加到IWeapon
接口和Person
类。 display
课程的Person
方法打印此人的媒体资源。同样,在单个武器实施的display
方法中打印武器的特性通过以上更改,您可以依靠单个界面直接在Person
类IWeapon
或DisplayPerson
对象上调用显示(不会违反单一责任原则):
public void DisplayAll() {
Console.WriteLine("Person " + pers.display() + "\n has weapon: " + iwep.display());
}
答案 1 :(得分:0)
有时令人困惑的是你可以遵循单一责任原则,所以没关系。
在回答您的问题之前,我想指出的代码有几个问题。
最后到你的实际问题
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
这看起来很好,它不违反单一责任原则。你在这个简单的例子中过度思考它。在上面的示例中,只有一个具有功能的类(显示人员)存在,其余的只是保存数据。将数据与功能分开时,这是一件好事。检查Single责任是否被破坏的一种简单方法是根据类的名称检查方法名称。如果它不合适,那么你违反了SRP。