I am new to object oriented design and learning about interfaces and design patterns. In this example, I am trying to create class for cars. My question:
Is it good practice to use base class and then inherit from it. And then use interfaces for implementing different functions? If not, then what would be the best way to implement this.
Base Class:
class BaseCar
{
public string color { get; set; }
public double price { get; set; }
public string carType { get; set; }
}
Interface:
interface ICarFunctions
{
void brakeSystem();
void drivingModes(string mode);
void entertainmentSystem();
}
Now I am trying to create concrete classes
class BmwCar : BaseCar, ICarFunctions
{
public void brakeSystem()
{
Console.WriteLine("Brake in less than 0.02ms");
}
public void drivingModes(string mode)
{
switch(mode)
{
case "mountain":
{
Console.WriteLine("Switching to 4x4 mode");
break;
}
default:
{
Console.WriteLine("Normal Mode");
break;
}
}
}
public void entertainmentSystem()
{
Console.WriteLine("Music, Navigation");
}
}
Now my question is: Is it good practice to use a base class and then inherit from it? And then use interfaces for implementing different functions?
My second question is if interface should have only one function (Single responsibility principle) or can it can have multiple functions which need to be implemented?
Best Answer
Your first question
There is no inherent requirement which states that methods should be implemented via an interface and fields/properties should be inherited/defined in the class. This is not a good way to separate the logic, as you're essentially preventing any meaningful relation to exist between a class' fields/properties and its methods.
One obvious limitation is that interfaces only deal with public members. If you applied your approach to the letter, it would be impossible to use private class methods.
Similarly, you'd be unable to define a public property via an interface, which is going to hamper the usability of your interfaces. As a simple example, IList exposes public properties like
Count
andIsReadOnly
. Could you technically handle that by using methods (GetCount()
andIsReadOnly()
)? Sure, but what is the point of forcing yourself to only using methods for public access? Public properties exist for a reason: to severely cut down on the boilerplategetFoo()
/setFoo()
methods that you'd end up having to write for every publically accessible field you want.Another limitation is that your code never defines that a
BaseCar
has abrakeSystem()
method. For example, there is no problem with making aBaseCar
that does not implement the necessary interface.The compiler has no issue with this. You never stated that you expect both the base class and interface to be used in conjuction with each other. This means that you're unable to create a method which is able to handle any
BaseCar
and make it brake. This is impossible:This means that your base class has become impossible to use for a lot of common polymorphism use cases, and you would end up constantly having to do
if(car is ICarFuntions) car.brakeSystem();
, which violates LSP and OCP.What you would expect is to be able to handle your base type without needing to guess about any interfaced the actual derived type might implement.
But this requires both the base and derived class to share the same method signature (regardless of whether the derived classes override the base class' method body or not).
When you do put your methods in an interface, the only way to ensure that this still works is to have the base class implement the interface.
The derived class doesn't directly implement the interface itself, it merely inherits the interface implementation from its base class (and then chooses to override it, but that's not a requirement, it could choose to keep the base method as is).
But when you get to that point, you might not even need the interface anymore since you're already stuck having to define the implementation in the base class anyway, which means the interface might be a pointless second layer; unless this interface is used in many different classes and has its own (different) fuctional purpose compared to the base class.
Your second question
There is no rule about the amount of methods. It's all about the functional independence. For more information, read up on the interface segregation principle (ISP), the I in SOLID. (Note: I just picked one link, many other references exist).
In essense, it boils down to whether your interface can be split or not. Let's take your case:
The first question you should ask yourself: is this a package deal? Does every car with a brake system have an entertainment system? Does every car with a driving mode have brakes?
The contextual answer here is no. There is no inherent requirement that when you have brakes, you must have an entertainment system, and thus this interface can be split into separate interfaces.
However, that's not the same as saying that an interface can only have one method. There are cases where you cannot split an interface, e.g.:
These standard media player functions can be considered a package deal. It makes no sense to only have some of these features. Therefore, this interface should not be split up any further since it would not make sense to use only a subset of these functionalities and not the rest.