Does this give any code smell or violate SOLID principles?
public string Summarize()
{
IList<IDisplayable> displayableItems = getAllDisplayableItems();
StringBuilder summary = new StringBuilder();
foreach(IDisplayable item in displayableItems)
{
if(item is Human)
summary.Append("The person is " + item.GetInfo());
else if(item is Animal)
summary.Append("The animal is " + item.GetInfo());
else if(item is Building)
summary.Append("The building is " + item.GetInfo());
else if(item is Machine)
summary.Append("The machine is " + item.GetInfo());
}
return summary.ToString();
}
As you can see, my Summarize() is tied to implementation classes such as Human, Animal, etc.
Is this code violating LSP? (Any other SOLID principles?)
I smell a little something...
If your classes all implement IDisplayable, they should each implement their own logic to display themselves. That way your loop would change to something much cleaner:
public interface IDisplayable
{
void Display();
string GetInfo();
}
public class Human : IDisplayable
{
public void Display() { return String.Format("The person is {0}",
GetInfo());
// Rest of Implementation
}
public class Animal : IDisplayable
{
public void Display() { return String.Format("The animal is {0}",
GetInfo());
// Rest of Implementation
}
public class Building : IDisplayable
{
public void Display() { return String.Format("The building is {0}",
GetInfo());
// Rest of Implementation
}
public class Machine : IDisplayable
{
public void Display() { return String.Format("The machine is {0}",
GetInfo());
// Rest of Implementation
}
Then you can change your loop to something much cleaner (and allow the classes to implement their own display logic):
foreach(IDisplayable item in displayableItems)
summary.Append(item.Display());
seems like IDisplayable should have a method for the display name so you can reduce that method to something like
summary.Append("The " + item.displayName() + " is " + item.getInfo());
Yes.
Why not have each class implement a method from IDisplayable
that shows their type:
interface IDisplayable
{
void GetInfo();
public string Info;
}
class Human : IDisplayable
{
public string Info
{
get
{
return "";//your info here
}
set;
}
public void GetInfo()
{
Console.WriteLine("The person is " + Info)
}
}
Then just call your method as follows:
foreach(IDisplayable item in displayableItems)
{
Console.WriteLine(item.GetInfo());
}
Given the comment on this answer from the OP, I think the best approach would be to create a custom container class to replace IList<IDisplayable> displayableItems
which has methods like containsHumans()
and containsAnimals()
so you can encapsulate the icky non-polymorphic code in one place and keep the logic in your Summarize()
function clean.
class MyCollection : List<IDisplayable>
{
public bool containsHumans()
{
foreach (IDisplayable item in this)
{
if (item is Human)
return true;
}
return false;
}
// likewise for containsAnimals(), etc
}
public string Summarize()
{
MyCollection displayableItems = getAllDisplayableItems();
StringBuilder summary = new StringBuilder();
if (displayableItems.containsHumans() && !displayableItems.containsAnimals())
{
// do human-only logic here
}
else if (!displayableItems.containsHumans() && displayableItems.containsAnimals())
{
// do animal-only logic here
}
else
{
// do logic for both here
}
return summary.ToString();
}
Of course my example is overly simple and contrived. For instance, either as part of the logic in your Summarize()
if/else statements, or perhaps surrounding the entire block, you'll want to iterate over the displayableItems
collection. Also, you'll likely get better performance if you override Add()
and Remove()
in MyCollection
and have them check the type of the object and set a flag, so your containsHumans()
function (and others) can simply return the state of the flag and not have to iterate the collection every time they're called.
How about:
summary.Append("The " + item.getType() + " is " + item.GetInfo());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With