Online Book Reader

Home Category

Programming Microsoft ASP.NET 4 - Dino Esposito [295]

By Root 5443 0
In general, you should always consider splitting responsibilities in distinct classes when the two sets of functions have little in common. If this happens, the two resulting classes will likely change for different reasons and will likely be called from different parts of the application. In addition, different parts of the application will change for different reasons.

Another scenario that suggests the need to split a class into two (or more) is when the two sets of functions you identified in the original interface are large enough to require sufficiently complex logic of their own. In this case, you simply lower the level of granularity of your design a bit. However, the size is not always, and not necessarily, a good parameter to use to make a decision about SRP. A function can be complex and large enough to justify a breakup; however, if it’s not likely to change over time, it might not require a distinct class. Scenarios like this, however, represent a tough call, with no uniform guidance to help you determine what to do.

Finally, you should pay a lot of attention not to split the original class into small pieces. The risk of taking SRP to the limit is falling into the Overdesign anti-pattern that occurs when a system is excessively layered and each layer ends up being a thin wrapper around an if statement. As mentioned, SRP is a driving vector rather than a dogma. You should always keep it in your mind but never apply it blindly and blissfully.

The Open/Closed Principle


We owe the Open/Closed Principle (OCP) to Bertrand Meyer. The principle addresses the need of creating software entities (whether classes, modules, or functions) that can happily survive changes.

The purpose of the principle is to provide guidance on how to write components that can be extended without actually touching the source code. Sounds like quite an ambitious plan, doesn’t it? Let’s get at the formulation:

A class should be open for extension but closed for modification.

Honestly, I find the formulation a bit idealistic and bordering on magic. However, the principle is in itself quite concrete. It essentially says that the source code of the class must remain intact, but the compiled code must be able to work with types it doesn’t know directly. This can be achieved in just one way: abstracting aspects of the class that can lead to changes over time. To abstract these aspects, you can either use interfaces and code injection or generics.

OCP Canonical Example


Low coupling between interfacing modules is beneficial because it instructs the caller to work with an abstraction of its counterpart rather than with a concrete implementation. In their masterpiece Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994), the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) formulate a basic principle of object-oriented design as “Program to an interface, not to an implementation.”

The gist of OCP is all here. Code that is based on an abstraction can work with a concrete object it gets passed as long as this object is compatible with known abstraction. Behind the term “abstraction,” you can find at least two concrete syntax elements: a base class or an interface. Here’s the canonical example of a class—the Renderer class—that fully complies with OCP:

public abstract class Shape

{

public abstract void Render();

}

public class Renderer

{

public void Draw(IList shapes)

{

foreach(Shape s in shapes)

s.Render();

}

}

The abstraction is represented by the base class Shape. The Renderer class is closed for modification but still open for extension because it can deal with any class that exposes the Shape abstraction—for example, any class that derives from Shape.

Analogously, you can have a Renderer class that receives its working type as a generic argument.

OCP Real-World Considerations


OCP should not be taken literally. Like SRP, it works much better if used as a driving vector. Frankly, no significant class can be 100 percent closed for modification.

Return Main Page Previous Page Next Page

®Online Book Reader