The Dependency Inversion Principle (DIP or D in SOILD principles) in C#

What is the Dependency Inversion Principle?

Robert Martin defines it as “Depend on abstractions, not on concretions or, A. High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details B. Abstraction should not depend upon details. Details should depend upon abstractions.”
If you use both OCP and LSP strictly, you will notice how a new pattern or structure emerges from it that can be generalized into what is known as the Dependency Inversion Principle.
This is one of the most useful principles, as it allow us to design software that is flexible (easy to change or extend), robust (reacts well to changes i.e. doesn’t break everywhere) and reusable (the parts of the system are very decoupled and we can extract them and use them in other projects), and whose main aim is to address bad design. The cause of bad designed software – software that is rigid, fragile and inmobile (opposite to flexible, robust and reusable in this case) – is the heavy hard-coded dependencies between its modules. These dependencies can in turn force the need of a cascade of changes when we want to introduce a tiny little change in the system (rigidity), or can result in a chain of unexpected errors (fragility), and of course, make impossible to reuse code in other applications because everything is so entwined that we might as well bring together the whole system.

The DIP addresses this problem saying no to hard-coded and top-down dependencies. The high- level modules should not depend upon the low-level modules, everything has to depend upon abstractions (thereby we get and “inverted” dependency). This way, the high level modules don’t know exactly what they depend upon, they just know they are using something that must adhere to a given interface, and thus, everything that follows that interface contract can be plugged in (or plugged out). If you extend the principle to the whole system you end up with a set of highly decoupled modules, that are completely isolated from changes in other modules and that can be easily reused. You end up with a well defined set of interfaces or abstractions that define the policy of your system, and a set of concrete implementations that are connected via these abstractions.

Interface Segregation Principle (ISP or I in SOLID principles) in C#

What is Interface Segregation Principle (ISP)?

The interface segregation principle is one of the SOLID principles that states that the clients should not be compelled to implement an interface that contains declarations of members or operations that they would not need or never use. Such interfaces are known as “fat” or polluted interfaces (also called interface bloat) as they contain too many operations.
Rather than having a fat interface and have the clients consume them, it is a recommended practice to break the fat interface to one or more specific and cohesive interfaces. If your code violates the interface segregation principle, you can fix it by taking advantage of the Adapter design pattern.
Imagine a situation in which the type that implements the interface needs to use only a few methods of the interface but not all. So, implementing such an interface where not all of the methods are relevant to the type implementing the interface is not a good practice.
So, then what’s the solution or alternative? Well, you can break this fat interface into one or more interfaces if you have access to the interface source code. If it is that you have no access to the interface, all you can do is use the relevant methods and just ignore the other ones. You can just throw and instance of the NotImplementedException class from those methods of the interface you don’t need at all. Note that when you are implementing an interface in a class, you must implement all of its members – otherwise the compiler would flag an error.
Generally speaking, if an interface has methods that can be broken into groups, each serving a different set of clients, we say the interface is “fat” and violates ISP. According to SRP, it means the same interface is assuming multiple responsibilities. To solve this problem, the “fat” interface should be replaced with multiple client-specific interfaces.

Liskov substitution principle (LSP or L in SOLID principles) in C#

What is Liskov Substitution Principle (LSP)?

The Liskov substitution principle (LSP) is a collection of guidelines for creating inheritance hierarchies in which a client can reliably use any class or subclass without compromising the expected behavior. If the rules of the LSP are not followed, an extension to a class hierarchy—that is, a new subclass—might necessitate changes to any client of the base class or interface. If the LSP is followed, clients can remain unaware of changes to the class hierarchy. As long as there are no changes to the interface, there should be no reason to change any existing code. The LSP, therefore, helps to enforce both the open/closed principle and the single responsibility principle.
The definition of the LSP by prominent computer scientist Barbara Liskov is a bit dry, so it requires further explanation. Here is the official definition:
Barbara Liskov: If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program.
There are three code ingredients relating to the LSP:
1- Base type – The type (T) that clients have reference to. Clients call various methods, any of which can be overridden—or partially specialized—by the subtype.
2- Subtype – Any one of a possible family of classes (S) that inherit from the base type (T). Clients should not know which specific subtype they are calling, nor should they need to. The client should behave the same regardless of the subtype instance that it is given.
3- Context – The way in which the client interacts with the subtype. If the client doesn’t interact with a subtype, the LSP can neither be honored nor contravened.

LSP rules

There are several “rules” that must be followed for LSP compliance. These rules can be split into two categories: contract rules (relating to the expectations of classes) and variance rules (relating to the types that can be substituted in code).

What are contract rules?
These rules relate to the contract of the supertype and the restrictions placed on the contracts that can be added to the subtype.
– Preconditions cannot be strengthened in a subtype.
– Postconditions cannot be weakened in a subtype.
– Invariants—conditions that must remain true—of the supertype must be preserved in a subtype.

To understand the contract rules, you should first understand the concept of contracts and then explore what you can do to ensure that you follow these rules when creating subtypes.

What are the variance rules?
These rules relate to the variance of arguments and return types.
– There must be contravariance of the method arguments in the subtype.
– There must be covariance of the return types in the subtype.
– No new exceptions can be thrown by the subtype unless they are part of the existing exception hierarchy.

The concept of type variance in the languages of the Common Language Runtime (CLR) of the Microsoft .NET Framework is limited to generic types and delegates. However, variance in these scenarios is well worth exploring and will equip you with the requisite knowledge to write code that is LSP compliant for variance.

Open closed Principle (OCP or O in SOLID principles) in C#

What is Open closed Principle?

In 1988 the open closed principle (OCP) mentioned by Bertrand Meyer as: Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
Software that works should when possible not be changed when your application is extended with new functionality.
Instead it should be possible to extend the existing software with new functionality without any modification to the current codebase and without adding duplicate code or duplicate functionality.
The OCP handles the way you want to structure your code in order to yield one of the greatest benefits claimed for object oriented technology: reusability and maintainability.
The best way to implement the open closed principle is to first start with implementing the Single Responsibility Principle: a class should have one, and only one, reason to change. This will separate different concerns in your code.
The next step is represent these separate concerns by abstractions and let consumers of these concerns talk to these abstractions.
To state the open closes principle very straightforward way you can say :
– You should design modules that never change.
– When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.
Abstraction is the way to realize this principle.
Derivatives from an abstraction are closed for modification because the abstraction is fixed but behaviour can be extended by creating new derivatives of the abstraction.

Let’s continue this discussion with the new world of client, server and Web APIs. The open closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”.  For the sake of this post I will use the term “server” to describe a class in an API – a business object for example.  “Client” will be used to describe the consumer of a service – it could be a user interface component for example.  The client has a dependency on a server at some level, the server knows nothing about a client.

Let’s paraphrase what Bertrand Meyer said about this principle. I am paraphrasing his definition as stating that once a class is completed it could only be modified to fix errors.  If you wanted to add any new features or change the behavior in any way you had to create a new class.  Inheritance may be used to reuse code from the original class but the resulting interface of the new class need not be the same as the interface of the original class.  Consider client class A that depends on server class B.  Once A and B are working they would never change.  Now we create server C which is an extension of B (reuses implementation but may have a different interface).  We have extended the API by creating server C but we did not change A or B so A continues to behave correctly.  The focus here is on how we can extend our API but keep clients working by not changing any of the working code.

Robert Martin is credited with popularizing the more modern application of the principle which advocates the use of abstract interfaces.  With this approach, server implementations can be changed, and multiple server implementations can be created and substituted for each other in the client.  Again consider client class A that depends on server class B but this time B is an abstract class.  Now we create server class C which is a derivation of B.  Since client A is dependent on an abstraction, we can extend the client by passing it C without changing A.  The focus here is on opening the client to extension but closing the client to modification.

Meyer’s approach is better in that it shouldn’t be possible to break working client A by adding server derivation C.  The down side, however, is that our answer to all change is to add more code, client A will not be able to make use of server extension C, and refactoring of B is not allowed.  With Martin’s approach we are essentially saying “as long as we respect the interface, never mind what I do to the server”.  The down side here is that it is easy to imagine breaking client A by adding a poorly designed server derivation C or even by carelessly refactoring B and inadvertently adding a bug.  The upside is that with this approach, client A may be extended to make use of server C  without changing the client and since we have the freedom to refactor our servers we should have less code, we can make use of new language features where it makes sense, and we can reorganize things as our API evolves.  In short the resulting code should be easier to maintain.

Single Responsibility Principle (SRP or S in SOLID principles) in C#

What is Single Responsibility Principle?

 Robert Martin in the principles of OOD says:  “There should never be more than one reason for a class to change.” This means a class should concentrate on doing one thing. The SRP says a class should focus on doing one thing, or have one responsibility. This doesn’t mean it should only have one method, but instead all the methods should relate to a single purpose (i.e. should be cohesive).
For example, an Invoice class might have the responsibility of calculating various amounts based on it’s data. In that case it probably shouldn’t know about how to retrieve this data from a database, or how to format an invoice for print or display.
A class that adheres to the SRP should be easier to change than those with multiple responsibilities. If we have calculation logic and database logic and display logic all mixed up within one class it can be difficult to change one part without breaking others. Mixing responsibilities also makes the class harder to understand, harder to test, and increases the risk of duplicating logic in other parts of the design (decreases cohesion, functionality has no clear place to live).
Violations of the SRP are pretty easy to notice: the class seems to be doing too much, is too big and too complicated. The easiest way to fix this is to split the class.
The main trick in following the SRP is deciding how to define the single responsibility. There may be many ways to dissect a feature into responsibilities, but the ideal way is to use responsibilities that are likely to change independently, hence the official description: “A class should have one, and only one, reason to change”.

 

SOLID Principles in C#

What are SOLID principles? 

SOLID is an acronym for the first 5 principles of object-oriented design:

S stands for SRP “The Single Responsibility Principle”:  a class should have one, and only one, reason to change.
O stands for OCP “The Open Closed Principle”: you should be able to extend a class’s behavior, without modifying it.
L stands for LSP “The Liskov Substitution Principle”: derived classes must be substitutable for their base classes.
I stands for ISP “The Interface Segregation Principle”: make fine grained interfaces that are client specific.
D stands for DIP “The Dependency Inversion Principle”: depend on abstractions not on concrete implementations.

 

Copyright © All Rights Reserved - C# Learners