Is this breaking my SOLID Principle? - c#

I am trying to learn better programming practices using SOLID principles. Here I am working on a sample application of Shapes. I just want to know, am I breaking the principle anywhere.Below are classes and its code.
1. Base Class - Shape
public abstract class Shape
{
public abstract double Area();
public virtual double Volume()
{
throw new NotImplementedException("You cannot determine volume from here...Method not implemented.");
}
}
2. Classes for Shapes like Rectangle, Triangle etc implementing base class Shape.
public class Circle : Shape
{
public int Radius { get; set; }
public override double Area() { return 3.14 * Radius * Radius; }
}
public class Triangle : Shape
{
public int Height { get; set; }
public int Base { get; set; }
public override double Area()
{
return 0.5 * Base * Height;
}
}
public class Rectangle : Shape
{
public int Length { get; set; }
public int Breadth { get; set; }
public override double Area()
{
return Length * Breadth;
}
}
public class Square : Shape
{
public Square() { }
public int Side { get; set; }
public override double Area()
{
return Side * Side;
}
}
3. A factory class that returns Shape.
internal class ShapeFactory<K, T> where T : class, K, new()
{
static K k;
private ShapeFactory() { }
public static K Create()
{
k = new T();
return k;
}
}
Till here everything seems fine and looks good, but problem occurs when I implemented it. I am little confused here. Lets see the front end code first:
internal class Program
{
private static void Main(string[] args)
{
try
{
var c = ShapeFactory<Shape, Circle>.Create();
// this part is not clear to me. See the questions below
if(c is Circle)
{
var circle = c as Circle;
circle.Radius = 5;
Console.WriteLine(string.Format("{0}", circle.Area()));
}
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex.Message);
}
Console.Read();
}
}
QUESTIONS
Different shapes has got different properties like circle has Radius, triangle has base and height and so on , so i decided to keep my properties in child class. I knew, I can have that as virtual member in my base class. So Is there any way other than coded above.
If not, then what is the use of abstract class, if still I am typecasting my Shape object to circle object? I can simple use Circle c = new Circle(). I don't want unwanted checks like (if c is circle) and all.
What If , I am asked to implement a new method to get Circumference of a circle. Do I need to create a new Abstract class or put it in Circle class. But if I put it Circle, I think it will break very first principle of SOLID i.e. SRP
.
Kindly note, I don't my abstract class as a fat class having unnecessary or repeated properties.
Thanks in advance

What I usually do in this case is to pass constructor parameters in concrete classes. So i'd change your concrete shapes to something like:
public class Circle : Shape
{
public int Radius { get; set; }
public Circle(int radius) {
this.Radius = radius;
}
public override double Area() { return 3.14 * this.Radius * this.Radius; }
}
public class Rectangle : Shape
{
public int Length { get; set; }
public int Breadth { get; set; }
public Rectangle(int lenght, int breadth) {
this.Length = lenght;
this.Breadth = breadth;
}
public override double Area()
{
return Length * Breadth;
}
}
and so on
Now, I would use a factory method, so your fabric will now be like:
public abstract class ShapeFactory
{
abstract Create();
}
public class CircleFactory : ShapeFactory
{
private int radius;
public CircleFactory(int radius){
this.radius = radius;
}
protected override Shape Create()
{
return new Circle(this.radius);
}
}
public class RectangleFactory : ShapeFactory
{
private int length;
private int breadth;
public RectangleFactory(int length, int breadth){
this.lenght = length;
this.breadth = breadth;
}
protected override Shape Create()
{
return new Rectangle(this.length, this.breadth);
}
}
Notice that, now a factory know how to build a shape with constructor passed in its own constructor.
So, each time you want a diferent shape you will instantiate a new factory.
ShapeFactory factory = new CircleFactory(5);
Shape shape = factory.Create();
Console.WriteLine(shape.Area()));
I think this answer your 1st and 2nd question.
So, 3:
What you can do to dont modify your class is use the strategy pattern in order to pass at runtime how to implement this method:
public interface IPerimeter
{
int calculatePerimeter();
}
public class Circunference : IPerimeter
{
public int calculatePerimeter(Circle circle) {
return 2*pi*circle.radius;
}
}
public class Circle : Shape
{
public int Radius { get; set; }
private IPerimeter perimeter;
public Circle(int radius, IPerimeter perimeter) {
this.Radius = radius;
this.perimeter = perimeter;
}
public Circunference() {
perimeter.calculatePerimeter(this);
}
public override double Area() { return 3.14 * this.Radius * this.Radius; }
}
Hope this helps with your training.

Different child classes will have different properties, that's expected and ok. Normally not all derived classes have the exact same properties as their base class. There's no reason to force Shape to have a Radius. What advantage would you have? That's just opening the door for trouble. What's your ultimate goal with this? Having something like myShape.Dimension = value and not care if it's a radius, a side, etc.? Anything can be done, depending on your needs.
With your abstract class you can, for example, loop through a list of Shape and call Area() or Volume(), knowing that you will get your result (despite your still not implemented Volume). Also your base class could have some common code, which in this case you are not using. You could have for example a Unit property which could be cm, inches, meters, etc. and then have a method like this (silly example):
public string GetAreaString()
{
return string.Format("{0} {1}", this.Area().ToString(), this.Unit);
}
Just implement it in Circle, of course. Why would it break Circle's single responsibility? Your class is dealing with the calculation of its
related values, just like a string tells you if it's null or its length.

For me your example seems really over engineered. I think you should always implement the simplest thing that works nothing more nothing less. I know that this is an example code, because you want to learn the SOLID principles, but I think is important to be aware of how horribly wrong can go these principles in the wrong context. In your specific code: do you need to group all your shapes using the Shape class? I mean, do you ever plan to iterate through a list of Shapes and calculate the area and volume for them? If not, the inheritance has absolutely no point. In fact I would say that inheritance is overused these days, and when it is overused you end up with ugly inheritance dependency graphs. Regarding the factory class: Is construction of any of your "shape" objects particularly difficult, time consuming, tricky. Does your factory class provide some value or it is completely useless? In case it has no real reason to exist, I wouldn't use it, the new operator is far more clear.
I hope you don't mind my reply but I just wanted you to be aware of the fact that some SOLID principles applies in very specific scenarios. Forcing them in the wrong places may cause ugly and over complicated code. In some real world situations, if the questions above are answered with yes, your pattern seems OK. Otherwise the exact same pattern can over-complicate things without any real benefits. I guess my point is: just be aware, not every SOLID principle is good in any situation:).

This is extremely common problem. While learning SOLID is nice, it requires understanding of basic design principles like abstraction and indirection. The reason why you are confused is because there is no abstraction in your code.
Imagine you have code that wants to know shape's area, but it doesn't care what shape it is nor how to calculate that shape's area. Something like :
public void PrintArea(Shape shape)
{
Console.WriteLine(shape.Area());
}
This is THE CRITICAL PART of OOP design. Your example has absolutely nothing of this. Your example is just contrived piece of code that has no logic to it, let alone being SOLID.

Related

C# Using class specific member references that child "base" calls respect

I'm currently working on a codebase and struggling to find an optimal and clean solution. I've removed the context of the problem to help simplify it to its root components. The Scale property is a simplification for a more complex state of the class in the actual codebase. I have an idea (which I'll reference at the bottom) for how I could solve this issue - however the solution feels messy and just avoids the area I want to better understand.
Class Hierarchy
public class GreatGrandparent
{
public virtual int Scale { get; set; } = 1;
public virtual int GetTrueScale()
{
return Scale;
}
}
public class Grandparent : GreatGrandparent
{
public override int Scale { get; set; } = 2;
public override int GetTrueScale()
{
return Scale * base.GetTrueScale();
}
}
public class Parent : Grandparent
{
public override int Scale { get; set; } = 8;
}
public class Child : Parent
{
public override int Scale { get; set; } = 4;
}
Somewhere else in code:
public class Main
{
Child aChild = new Child();
int aChildTrueScale = aChild.GetTrueScale();
}
Expected Result: 4 (4×1) (Refer to Edit 1)
Actual Result: 16 (4×4)
Desired Result: 64 (4×8×2×1)
I want a child to find its relative scale by taking in all factors of scale from its parents, so that would like:
child relative scale = child scale × parent scale × … × base class scale
How can I (if possible) define the GetTrueScale method once in the parent class to get the desired result - which all children inherit - to avoid continuously overriding the method with duplicate implementations (the exception being the GreatGrandparent).
"Messy" Solution
Define a separate property/field in each class, and continuously override the aChildTrueScale() method with a return of ClassScale * base.GetTrueScale() where the ClassScale is a different property on each Class.
Edit 1
The expected result was my initial expectation based on my understanding at the time - thinking that within a base call the Scale reference would respect the change in scope change value to match that of the base class. With some further testing it appears that regardless of what scope when a base method is called, the referenced Scale value is always from the initial objects scope (hence 4*4).
Is it possible to refer to properties based on their scope? So in a base.GetTrueScale() call, any references within that function call will be on the base scope. Or am I completely missing something/trying to over simplify children?
Footnote
I've got a a bit of experience with procedural programming around data science, however I'm fairly inexperienced with object-oriented programming so forgive me if I'm ignorant to some core concepts. I’m happy to help clarify anything, thanks for taking the time to look over my first question! ^-^
(If anyone can think of a better title please let me know and I'll fix it up - was struggling to define the issue simply)
From the discussion in the comments, it turns out that you don't need your Scale property to be settable (its value is fixed on construction), and you don't even need it to be virtual. You can just have a single property on the GreatGrandfather class, like so:
public class GreatGrandparent
{
public int Scale { get; }
public GreatGrandparent(int scale)
{
Scale = scale;
}
}
public class Grandparent : GreatGrandparent
{
public Grandparent(int scale) : base(scale * 2) { }
}
public class Parent : Grandparent
{
public Parent(int scale) : base(scale * 8) { }
}
public class Child : Parent
{
public Child(int scale) : base(scale * 4) { }
}
In your actual code, you're dealing with a HashSet. You could write something like this, where each child adds new items to the GreatGrandparent's HashSet:
public class GreatGrandparent
{
protected HashSet<string> hashSet = new();
public GreatGrandparent()
{
hashSet.Add("itemOne");
}
}
public class Grandparent : GreatGrandparent
{
public Grandparent()
{
hashSet.Add("itemTwo");
}
}
Or pass down the items to add in the constructor chain (more expensive, but maybe neater?):
public class GreatGrandparent
{
protected HashSet<string> hashSet;
public GreatGrandparent(IEnumerable<string> items)
{
hashSet = new(items);
hashSet.Add("itemOne");
}
}
public class Grandparent : GreatGrandparent
{
public Grandparent(IEnumerable<string> items) : base(items.Concat(new[] { "itemTwo" })) { }
}
I'd suggest using the type system to model this hierarchy is a mistake. You're wanting Child, Parent, GrandParent to be separate, independent things. That doesn't suggest the is-a relationship that you typically expect in the type system.
So instead have:
public class Thingy {
public int Scale {get;set;}
public Thingy Parent {get;set;}
public int GetTrueScale()
{
var current = this;
var accumulator = current.Scale;
current = current.Parent;
while(current!=null)
{
accumulator = accumulator * current.Scale;
current = current.Parent;
}
return accumulator;
}
}
And then create each of your objects:
var greatGrandParent = new Thingy {Scale = 1};
var grandParent = new Thingy {Scale = 2, Parent = greatGrandParent};
var parent = new Thingy {Scale = 8, Parent = grandParent};
var child = new Thingy { Scale = 4, Parent = parent};
And you can now call child.GetTrueScale() and all levels of the hierarchy are taken into consideration.
Adding Children sets to Thingy and other more interesting behaviours is left as a exercise.
Thingy itself could also be an IThingy interface, if the different levels truly do require separate types.
The type hierarchy will be called in the order from most base type -> most derived.
As you do not have overriden methods in Parent then your Scale is not multiplied. That it is a reason why you got 16. It is better to debug and see order of execution of your code.
You can add override GetTrueScale() method of class Parent to have desired value 64. The whole code will look like this:
public class GreatGrandparent
{
public virtual int Scale { get; set; } = 1;
public virtual int GetTrueScale()
{
Console.WriteLine("GreatGrandparent: " + Scale);
return Scale;
}
}
public class Grandparent : GreatGrandparent
{
public override int Scale { get; set; } = 2;
public override int GetTrueScale()
{
Console.WriteLine("Grandparent: " + Scale);
return Scale * base.GetTrueScale();
}
}
public class Parent : Grandparent
{
public override int Scale { get; set; } = 8;
public override int GetTrueScale()
{
Console.WriteLine("Grandparent: " + Scale);
return Scale * base.GetTrueScale();
}
}
and Child class:
public class Child : Parent
{
public override int Scale { get; set; } = 4;
}

Is pattern matching by property existence possible in C#?

Lets say we have this example hierarchy:
abstract class Shape { }
class Circle : Shape
{
public int Radius { get; set; }
}
class Rectangle : Shape
{
public int A { get; set; }
public int B { get; set; }
}
I am wondering if it's possible to use pattern matching in C# on a variable of type Shape to determine if it has property Radius e.g.
// Imaginary syntax
if (myShape is { int Radius} )
{
}
I have not found that this is possible, so I assume the answer is no, but probably someone knows better.
Alternatives that I can think of:
Enumerate all the known scenarios (i.e. of Type Circle, etc.), downside is that an introduction of a new type in the future will break it
Introducing an interface, which might be cumbersome depending on the scenario
Using reflection (not too nice)

Do split one class hierarchy into several or not?

For now, we have a .NET application that leans on the standard .NET XML serialization/deserialization mechanism. The example is simplified but the meaning is the same.
public abstract class Shape
{
[XmlAttribute("id")]
public string Id { get; set; }
[XmlAttribute("level")]
public int Level { get; set; }
public abstract void Draw();
public abstract void Clear();
public abstract void Scale(double scale);
}
[XmlType("Circle")]
public class Circle : Shape
{
public double Radius { get; set; }
public override void Draw() {}
public override void Clear() {}
public override void Scale(double scale) {}
}
[XmlType("Rectangle")]
public class Rectangle: Shape
{
public double Height { get; set; }
public double Width { get; set; }
public override void Draw() {}
public override void Clear() {}
public override void Scale(double scale) {}
}
public class Picture
{
public double Scale { get; set; }
[XmlArrayAttribute("Shapes")]
public Collection<Shape> Shapes { get; set; }
public void Setup()
{
foreach (Shape shape in Shapes)
{
shape.Draw();
}
foreach (Shape shape in Shapes)
{
shape.Scale(Scale);
}
}
public void Cleanup()
{
foreach (Shape shape in Shapes)
{
shape.Clear();
}
}
public static Picture FromXml(XmlReader xmlReader)
{
XmlSerializer serializer = new XmlSerializer(typeof(Picture));
return serializer.Deserialize(xmlReader) as Picture;
}
}
And for example the input XML file will look like:
<Picture>
<Scale>0.9</Scale>
<Shapes>
<Circle id="1">
<Radius>1.5</Radius>
</Circle>
<Circle id="2">
<Radius>3</Radius>
</Circle>
<Rectangle id="3">
<Height>300</Height>
<Width>300</Width>
</Rectangle>
</Shapes>
</Picture>
But model classes contain a logic (Draw(), Clear() and Scale() methods) and it seems that it breaks a single responsibility principle. And therefore we don't know does it make sense to split that logic into several classes or not?
If yes, then how? Because once we read the XML file, all objects are accessible only as Shape objects and therefore we will have to explicitly cast the object either before passing if to the handler class or inside that method, for example:
public abstract class Drawer
{
public abstract void Draw(Shape shape);
}
public class CircleDrawer : Drawer
{
public override void Draw(Shape shape)
{
Circle circle = shape as Circle;
if (circle == null)
{
throw new ArgumentException("Passed object is not of type Circle");
}
}
}
If that issue is known, please just redirect me to that resource.
Thank you in advance.
You should separate the model and business logic,
So the object that will be deserialized will contain only the properties.
Then, in the factory or method that creates the business logic, insert it as a member of the circle (for example) business logic.
Trying to separate model and business logic I get the following code. Is it acceptable? As for me, it looks not flexible: we should not forget to extend the if statement if we add a new shape drawer.
public abstract class Drawer
{
public abstract void Draw();
}
public class CircleDrawer : Drawer
{
private readonly Circle _circle;
public CircleDrawer(Circle circle)
{
_circle = circle;
}
public override void Draw() { }
}
public class RectangleDrawer : Drawer
{
private readonly Rectangle _rectangle;
public RectangleDrawer(Rectangle rectangle)
{
_rectangle = rectangle;
}
public override void Draw() { }
}
public class Picture
{
public double Scale { get; set; }
[XmlArrayAttribute("Shapes")]
public Collection<Shape> Shapes { get; set; }
public void Setup()
{
List<Drawer> drawers = new List<Drawer>();
foreach (Shape shape in Shapes)
{
if (shape is Circle)
{
drawers.Add(new CircleDrawer(shape as Circle));
}
else if (shape is Rectangle)
{
drawers.Add(new RectangleDrawer(shape as Rectangle));
}
else
{
}
}
foreach (Drawer drawer in drawers)
{
drawer.Draw();
}
}
public static Picture FromXml(XmlReader xmlReader)
{
XmlSerializer serializer = new XmlSerializer(typeof(Picture));
return serializer.Deserialize(xmlReader) as Picture;
}
}
The question in this case would be, is it needed that the caller knows the concrete type or is everything mapped through the common base class?
In your example all implementations share a common abstract base class. If all users can happily work with this common behaviour you just push around all instances casted to the base type. Nevertheless as you already mentioned this tends to put more and more business logic into each concrete class. Depending on how much (or better less) this is, it is absolutely okay to let it there (this seems to be your current solution).
If this is getting more or quite complex it would be a good way to move this into its own class and/or methods. In that case you need some kind of dispatcher, that decides which takes care for the given object. I start to use a dictionary for these cases that works as a dispatcher and has the given type as key and an Action or Func as value like this:
var dispatcher = new Dictionary<Type, Action<Shape>>
{
{ typeof(Rectangle), DoSomethingWithRectangle },
{ typeof(Circle), DoSomethingWithCircle }
}
private void DoSomethingWithRectangle(Shape shape)
{
var rectangle = (Rectangle)shape;
Console.WriteLine($"Rectangle Height: {rectangle.Height} Width: {rectangle.Width}");
}
private void DoSomethingWithCircle(Shape shape)
{
var circle = (Circle)shape;
Console.WriteLine($"Circle Radius: {circle.Radius}");
}
This is just a trivial example. The dictionary should be live within a dispatcher where you have some methods to register different types and instead of methods you could also register types or instances of classes that could handle each specific instance type. If this kind of dispatching is still not matching all your cases you could maybe take a look at MediatR which formalized these things much more with a bunch of type-safe interfaces which you use to define your input types, the desired return value and an handler that is capable of doing this job.

How to programmatically assign two different classes to one variable?

I am creating a game in Unity and I have 2 classes, I want to assign that variable with 2 different classes depending on a boolean value, to later use that class how I wish, here is the code I have so far to give an idea what im looking for, is it even possible for it to be done? Thanks
public GeneticController geneticController;
public GeneticDriver geneticDriver;
public Object Genetic;
void Start() {
if (RaceSelect.SelectedRace == 2) {
Genetic = geneticDriver;
} else {
Genetic = geneticController;
}
}
void FixedUpdate() {
float steer = (float)(Genetic.Steering);
Steering(steer);
}
At the moment It just says, that Object doesn't have a variable called "Steering". What type should Genetic be?
I am making some assumption here, that both GeneticController and GeneticDriver implement a Steering property? If so, and especially if they have additional properties and methods in common, the proper way to implement this is to refactor the classes so that they share a common interface.
public interface ISteering
{
float Steering {get; set;}
}
public class GeneticController : ISteering
{
public float Steering{ get; set; }
}
public class GeneticDriver: ISteering
{
public float Steering{ get; set; }
}
For there you can make your variable Genetic a type of ISteering.
public ISteering Genetic;
However, if Steering is the only property they have in common, I recommend you taking a second look at your overall design. If the two classes share no, or very little, common functions, they probably don't need to share a variable.
Have you tried using a base class that is derived into your 2 sub-classes?
Something along the lines of:
public class BaseClass
{
public float Steering {get;set;}
}
public class GeneticController : BaseClass
{
}
public class GeneticDriver : BaseClass
{
}
then you do the following (and you do not need the cast):
BaseClass Genetic
void Start()
{
if (RaceSelect.SelectedRace == 2)
{
Genetic = geneticDriver;
} else
{
Genetic = geneticController;
}
}
void FixedUpdate()
{
float steer = Genetic.Steering;
Steering(steer);
}
You could set the BaseClass as an interface also. It depends if you have common functionalities, or not, between you 2 derived classes.

When I type objects is there any difference between me using an Interface or a class?

I created this interface:
public interface IPhrase
{
int CategoryId { get; set; }
string PhraseId { get; set; }
string English { get; set; }
string Romaji { get; set; }
string Kana { get; set; }
string Kanji { get; set; }
}
and this class:
public class Phrase : IPhrase
{
public Phrase()
{
}
public int CategoryId { get; set; }
public string PhraseId { get; set; }
public string English { get; set; }
public string Romaji { get; set; }
public string Kana { get; set; }
public string Kanji { get; set; }
}
Here this code returns data and typecasts it to Phrase:
var phrases = db2.Query<Phrase>("SELECT * FROM Phrase", ans);
var phrases = db2.Query<IPhrase>("SELECT * FROM Phrase", ans);
What I would like to know is if there is any difference / advantage in my using the IPhrase here or Phrase? Also what advantages are there (if any) in my creating a IPhrase interface in this example. Does that lead to more readable code?
An interface is a contract that guarantees, any class implementing the interface will implement the methods and properties defined in the interface. This allows you to use the interface to create methods, lists, etc. which accept any class that implements the interface e.g.
public interface IExample
{
int GetInt();
}
public void ProcessInt(IExample value)
{
var tempInt = value.GetInt();
// Do processing here
}
This allows any concrete class that implements interface IExample to be passed to this method. The method is assured that any concrete class passed will have the method GetInt implemented.
With objects you can inherit from to things:
Other Objects
Interfaces
Object
If you have an Animal object, a Dog object can inherit from it as it is an animal.
With Object inheritance think of the phrase: I am a ...._yourObject_...
Interface
With an interface you can think of it as a describer for that object. Such as IWalkOnTwoLegs or ICanSwim.
So think of the phrase : I can do ...._yourInterface_..
Now to answer your question, would it make a difference if you use an interface or not?
Well, it wouldn't in this case but if you extend your phrases and create a Question object and a Statement object, for example, and they inherit from Phrase, you have a choice where you can return all phrases (questions and statements) or only phrases that are Questions or only Statements.
You can also apply an interface saying IAmInFrench and IAmInSpanish to your phrase so you can have extended SpanishPhrase and FrenchPhrase objects.
Now you can return either all phrases whether they are questions, statements, in a different language, or you can be specific and return only french phases.
Where I find interfaces are most useful are for registration of different types in unity.
Where it will make a difference:
Where it will definitely make a difference is if there is a property on the object that isn't on the interface, then if you return the interface you will not be able to access that property very easily unless you type cast.
eg:
public class Phrase : IPhrase
{
public Phrase()
{
}
public int CategoryId { get; set; }
public string PhraseId { get; set; }
public string English { get; set; }
}
And interface
public interface IPhrase
{
int CategoryId { get; set; }
}
You will not be able to access the property English if you return the interface:
var phrases = db2.Query<IPhrase>("SELECT * FROM Phrase", ans);
var eng = phrases[0].English; //**THIS WONT WORK**
There is no difference between using an interface and a concrete object locally, as in your example. The main difference is when you are sending interfaces vs concrete classes as parameters in APIs or constructors parameters, where is preferably using interfaces so you can achieve decouple and testability.
Still for your question the short answer is no, there is no difference, whether you want to use interfaces or concrete objects as local variables is your own choice (what seems more readable to you). Do not forget that fields and properties are good to be declared as interfaces which provides more flexibility.
One last thing which should be considered when using a concrete object instead of an interface even locally is that you may want someday to change the signature of the method which provides you that object to return another kind of object which implements the same interface, and in that case you should change the local variable too (even if it's not so bad and it happens very rarely I had to note it), as in the following example:
interface IAnimal
{
void Run();
}
class Cat : IAnimal
{
public void Run()
{
//...
}
}
class Dog : IAnimal
{
public void Run()
{
//...
}
}
If in your code you have a method which returns a Cat that you use:
Cat GetAnimal()
{
return new Cat();
}
Cat myAnimal = GetAnimal(); //note that here it is expected a Cat
myAnimal.Run();
Then if you change the GetAnimal signature to return a Dog, your code should be changed in order to compile to:
Dog myAnimal = GetAnimal(); //note that here it is expected a Cat
myAnimal.Run();
But if you are using an interface there are less chances that your code will need to be changed when method's signatures ar changed:
IAnimal myAnimal = GetAnimal(); //this is working whether a Cat or a Dog is received.
myAnimal.Run();
But again this is happening relatively rarely. Sorry for the silly Cat & Dog example!
A class is a template for an object. It is essentially a blueprint. So for a light there a button that is on and off. Say when you call this method a value is sent to some controller that turns it on and off. All you have to do is call the method for on/off and viola it works.
An interface is very similar. Here the on/off method might not be implemented. You actually have to go and write the code to turn the light on and off but you must write the on/off method or it cannot be that interface. Say there is a new type of light that has dimming functionality. An interface allows you to implement this new feature for a different type of light. So its basically telling you that you have to have this stuff done (on/off) for it to be a light but we don't care how you implement it. Some parts of the interface may be implemented for you, but other parts you have to implement.
When would an interface make sense? A situation where you have many objects that are very similar in nature but differ slightly in implementation. For example say you have many types of shapes. Each is going to have an area. The calculation is different for a triangle than it is for a circle. Now say you have hundreds of shapes that need to be constructed, you wouldn't keep making new objects for each type of shape, you would just implement the interface. This gives somebody the power to create shapes, maybe even custom shapes, with similar methods but different implementations.
Your answer depends on the way you want to use your future classes. Interfaces are contracts to ensure descendant classes have all definitions of interface. So This is useful when you want to use polymorphism. in this way, you can define all common specifications of an object in an interface class. Another advantage of interfaces is that your class can inherit from multiple interfaces, which is not allowed for other type of classes in C#. Here is an example code. Hope to be useful for you:
public interface IShape
{
float Area { get; }
float circumference { get; }
}
public class Rectangle : IShape
{
private float l, h;
public Rectangle( float length, float height ) { l = length; h = height; }
public float Area { get { return l * h; } }
public float circumference { get { return ( l + h ) * 2; } }
}
public class Circle : IShape
{
private float r;
public Circle( float radius ) { r = radius; }
public float Area { get { return (float)Math.PI * r * r; } }
public float circumference { get { return (float)Math.PI * r * 2; } }
}
public class SomeClass
{
IShape[] shapes = new IShape[] // Can store all shapes regardless of its type
{
new Rectangle( 10f, 20f ),
new Rectangle( 15f, 20f ),
new Rectangle( 11.6f, .8f ),
new Circle( 11f ),
new Circle( 4.7f )
};
public void PrintAreas()
{
foreach ( var sh in shapes )
Console.WriteLine( sh.Area ); // prints area of shape regardless of its type
}
public void PrintCircumference(IShape shape )
{
Console.WriteLine( shape.circumference ); // again its not important what is your shape, you cant use this function to print its cicumference
}
}

Categories

Resources