This is part 5 in a series on Software Gardening. If you’re just jumping in, you can find Part 1 here.
Plants start with seeds. We need good seeds to create great software. Our seeds are good OOP practices. Each of the concepts I will talk about could be a single post on their own. If you want to drill into the concepts more (something I encourage), there is lots of information available on the interwebs.
Let’s do a quick review of some basics, starting with inheritance. We can create a class, then subclass that. The first class is the parent and the subclass is the child. The child will inherit attributes (properties) and behavior (methods) from the parent. There are actually two types of inheritance. The first is implementation inheritance. This is where you put functionality into the parent class and the child inherits it. If a method is not defined in the child class, the parent class method is used. You can also override the behavior in the parent so that what you define in the child is what gets run.
The second type of inheritance is interface inheritance, where you simply define some some public members and the signature of each method. The parent has no functionality. The child class must inherit each method in the parent, but is not required to provide functionality in each.
The second basic concept is polymorphism. This is where you can have two things named the same that do different things. For example, the Click method of a command button does something different than the Click method of a radio button.
Next is encapsulation. This means that a class hides it’s internal data from the outside world. It also means that a class data and the methods it uses are defined together.
Now for what I call intermediate OOP concepts. The first of those is loose coupling. What this means is that classes don’t necessarily know about each other. Do you instantiate a class every time you need it or do you pass in a reference to a class or create a static class to make it easier to get to? The less we instantiate one class from another, the more loosely the classes are coupled. And this is good because it makes it easier to update or even completely replace loosely coupled classes.
This brings us to loose coupling’s cousin, tight cohesion, which is a measure of how functionally related the different parts of a class are. You want to strive for everything in a class to be closely related, thus tight cohesion. This is desirable because it results in a class being changed less often because it does fewer things and that leads to fewer bugs.
The last five concepts are considered advanced by many people. But, I think they are more basic than than, but are very important. So important in fact, that they have been called SOLID because the first letter of each principle spells SOLID. They’ve been around for some time, but were compiled together by Robert “Uncle Bob” Martin in his book Agile Principles, Patterns, and Practices in C# (a book that I highly recommend).
The first SOLID principle is the Shgle Responsibility principle. The responsibility of the class is what it does. We’re talking about the behavior of the class. A class should have only one responsibility, it should do one thing. Sometimes it’s difficult to determine what that one thing is. If in doubt, split the class in two. When a class does one thing, there is less chance to introduce bugs because you will modify the class less often.
Next is the Open-Closed principle. This principle says that a class should be open for extension, but closed for modification. Wait! What? How can a class be both open and closed? What this principle says is that you should be able to add new functionality to a class without modifying the source or even the the binary of that class. In .Net, you can do this with partial classes, extension methods, and inheritance.
The L of SOLID is the Liskov Substitution Principle, which tells us that you should be able to substitute a child class for its base class without any of the classes that use it knowing that the substitution was made.
The Interface Segregation principle is next. Over time, an interface will grow as new functionality is added. At some point, the class will become bloated. This principle says that when this happens, you should split the interface into smaller pieces so that the client does not have to rely on methods it doesn’t use. Following this principle makes your code decoupled and easier to maintain, enhance, and extend.
Finally, we’re at the Dependency Inversion principle. This is basically inversion of control (IoC) or dependency injection (DI). When following this principle, you pass in a reference to a class rather than new-ing. It makes it easy to change the class that is used. Just have two classes that inherit from the same interface and pass in the one that you need. Again, this decouples the classes.
So, in a nutshell, that’s SOLID. By following these principles, your application will be better designed and better able to withstand change.