I am having difficulty finding a best practice in C# for 'base' classes.
Is it true that base classes should only contain variables/properties that are used by EVERYTHING that inherits it?
My example is a property is used by 3 out of the 7 classes that inherit the base class.
public class UpgradeBase
{
Public bool IsToggleable { get; set; } = false;
}
public class UpgradeBuilding : UpgradeBase
{
//This class needs to access IsToggleable
}
public class UpgradeScience : UpgradeBase
{
//This class does NOT need to access IsToggleable and never uses it
}
Should I be only including this property in the classes that will be using it (the 3 out of 7 classes that actually need this property), or is it 'ok' to define it in the base class (even though 4 out of 7 won't ever care about it)?
CodePudding user response:
As a rule, a class should only include things that it needs - whether that's in a base class or a descendant class.
I'd probably add a second "base" class that adds the isToggleable feature, and let those classes that need it derive from that intermediate ancestor.
Something like:
public class UpgradeBase
{
}
public class UpgradeToggleable : UpgradeBase
{
public bool IsToggleable { get; set; } = false;
}
public class UpgradeBuilding : UpgradeToggleable
{
//This class needs to access IsToggleable
}
public class UpgradeScience : UpgradeBase
{
//This class does NOT need to access IsToggleable and never uses it
}
However, doing this for one field is a bit of overkill. Be wary of creating a "god class" that implements everything that every descendant might need. That is a good way to wind up with an unmaintainable mess.
Another approach is to favor composition over inheritance. Common functionality that doesn't fit well in a strict hierarchy could be implemented in its own component class. Classes that need those features could include a field of that component type. This is one of the ideas behind so-called Entity/Component/System architectures.
CodePudding user response:
"Is it true that base classes should only contain variables/properties that are used by EVERYTHING that inherits it?"
Not really. Base classes are normal classes. A base class is simply a superclass of a subclass. They contain any kind of member. Like classes in general, they must implement everything to satisfy their responsibility.
The logic of a base class will be inherited by its subclasses so that they can reuse the functionality.
If a Vehicle
has an Engine
and can Move()
, then it can be the base class of a Car
, Truck
, Airplane
, Train
etc.
As you can see, a subclass extends its base class. Following a good class design, subclasses should not inherit useless members. For example the Airplane
class should not inherit the Dive()
functionality because it is of no use. Your class design must respect such cases. It would make more sense to redesign the inheritance tree and introduce a base class for marine vessels and air vessels.
Ideally, the subcalsses don't know the details about what they are inheriting. Some functionality must be overridden (virtual members) to adjust to the more specialized subclass. The idea is to encapsulate the logic that is shared amongst related types.
You should always consider to define a base class abstract, especially if it requires to be derived from in order to operate meaningful.
Inheritance is a fundamental in object oriented programming. You will find enough resources on the web like eBooks, blogs or tutorials to teach you.
"Should I be only including this property in the classes that will be using it (the 3 out of 7 classes that actually need this property), or is it 'ok' to define it in the base class (even though 4 out of 7 won't ever care about it)?"
You should define an interface IToggleable
. Then implement this interface on those types that need to be toggleable.
CodePudding user response:
You should use base classe for class who need to implement the same properties / methods, and use interface on your derived classe who need "special properties"
public class UpgradeBase
{
// Implement common properties and method
}
public interface IToggleable
{
bool IsToggleable { get; set; }
}
public class UpgradeBuilding : UpgradeBase, IToggleable
{
//This class needs to access IsToggleable
public bool IsToggleable { get; set; } // Interface implementation
}
public class UpgradeScience : UpgradeBase
{
//This class does NOT need to access IsToggleable and never uses it
}