Reputation: 97
I am learning SOLID Principles. I am working now with Dependency Injection and Interface Segregation Principles. I've already got the basics of this two but when I combined it, I got confused. Here's my implementation..
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());
}
}
I created another class for displaying information as "S" rule in SOLID says that a class shouldn't do which it is not supposed to do. And I think displaying that information is not its task. (Please correct me if I'm wrong)
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();
}
With this interface IWeapon, I can now able to add many weapons that have weaponName and damage. But if I want to add another weapon with added functions, we have to follow the ISP principle, right? So I created this interface and class below.
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();
}
And I implemented it like this..
static void Main(string[] args)
{
DisplayPerson disp = new DisplayPerson(new Sword("Samurai Sword", 100), new Person("Jheremy", 19));
disp.DisplayAll();
Console.ReadKey();
}
My problem is how do I inject IWeaponv1 to DisplayPerson class above? Is it possible or my understanding in SOLID principles is just wrong. Please correct me if you see that I've done something wrong or bad practice :)
Upvotes: 2
Views: 533
Reputation: 15212
The implementation that you present in your question looks good from a theoretical point of view; however, it does have some design issues in the real world.
While the Single Responsibility Principle does promote more cohesive classes, it should not be extended to a level where every functionality is moved to a new class. Case in point is the DisplayPerson
class which is not required at all (or should be implemented differently which I will discuss shortly). Classes represent real world objects. In the real world, if you ask a person their name, they would tell you their name rather than redirect you to another person who tells you their name. A Person
object is therefore allowed to have a method for printing it's own properties and this does not defy the Single Responsibility Principle in any way. Same goes for the weapons as well.
Consider that you want to print the range
of a weapon if the weapon supports this functionality/behavior. As it stands, the DisplayPerson
has-a IWeapon
reference but IWeapon
does not have ranges
as part of it's contract. How then do you print the range
of a weapon? (range
will not be accessible through iwep
reference in the DisplayAll
method). You will have to use a typeOf
check and then downcast IWeapon
to IWeaponV1
so that you can call the ranges
method. The problem with this approach is that DisplayPerson
will now have to work with two different interfaces rather than working with a single interface. (Not to mention the conditional checks that defy the purpose of using a common interface)
Keeping the above points in mind, you can make the following code changes :
display
method to IWeapon
interface and Person
class. display
method of Person
class. Similarly, print the properites of a weapon in the display
method of the individual weapon implementationWith the above changes, you can call display directly on your Person
or IWeapon
objects in the DisplayPerson
class by relying on a single interface ( without violating the Single Responsibility Principle) :
public void DisplayAll() {
Console.WriteLine("Person " + pers.display() + "\n has weapon: " + iwep.display());
}
Upvotes: 1
Reputation: 7903
It's sometimes confusing with far you can follow Single responsibility principle, so its alright.
There are a couple of issues on the code I would like to point out before answering your questions.
Finally to your actual question
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
This looks fine, it doesn't violate single responsibility principle. You are overthinking it in this simple example. In the above example, only one class(Display person) with functionality exists and rest of them are just holding data. That's a good thing when you separate data from functionality. A simple way to check if the Single responsibility is broken is by checking the method name against the name of the class. If it's out of place then you are violating SRP.
Upvotes: 0