Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
SOLID PRINCIPLE
OCP :Open/Closed Principle
Extension points
Extension PointsClasses that honor the OCP should be open to extension by
containing defined extension points where future functionality can hook into the existing code and provide new behaviors.
Code without extension points
Extension Points (cont’d)
f you allow changes to existing code where they have no client impact, you might not have to create an entirely new version of the TradeProcessor.
If the ProcessTrades method signature were to change, this would not simply be an implementation change for the class, it would also be an interface change.
All interface changes force client changes because clients are tightly coupled to the interfaces of their dependencies.
Extension Points: Virtual Methods
An alternative implementation for the TradeProcessor
class contains an extension point: the ProcessTrades
method is virtual.
Any class that marks one of its members as virtual
is open to extension
This type of extension is via implementation
inheritance.
When the requirement for a new feature in the
TradeProcessor class arrives, you can subclass the
existing TradeProcessor and—without modifying its
source code—alter the ProcessTrades method.
The TradeProcessorClient does not need to change in
this case. Because
It is possible to use polymorphism to supply the
client with the new version of the TradeProcessor
It is possible to call the subclass’s implementation
of the ProcessTrades method.
Virtual Methods (cont’d)
If we allow changes to existing code where they have no client impact, we might not have to create an entirely new version of the TradeProcessor.
If the ProcessTrades method signature were to change, this would not simply be an implementation change for the class, it would also be an interface change.
All interface changes force client changes because clients are tightly coupled to the interfaces of their dependencies.
Extension Points: Abstract Methods
A more flexible extension point that uses implementation inheritance is an abstract method.
The TradeProcessor is an abstract class that defines a public ProcessTradesmethod, which delegates the work of the processing algorithm to three protected abstract methods.
The client has no knowledge of these protected methods and, because they are abstract, no implementation is provided.
Abstract methods (Cont’d)
These methods need not be abstract; they could be virtual.
The difference here is mainly the granularity of what has been made extensible.
Rather than replacing the ProcessTrades method in its entirety, you can now replace select parts of the process by overriding the constituent methods.
Virtual Functions in Java
In Java, all non-static methods are by default "virtual functions."
Only methods marked with the keyword final cannot be overridden
The methods are private methods
The methods are not inherited,
The methods are non-virtual.
Extension Point: Interface Inheritance
The client depends on an interface rather than a class.
Interface inheritance is preferable to
implementation inheritance.
With implementation inheritance:
all subclasses are clients.
This prevents modification
subclasses depend on the
implementation
All implementation changes are
potentially client-aware changes.
The advice is to prefer composition over
inheritance and to keep inheritance
hierarchies shallow, with few layers of
subclassing.
If a change is made to add a member at
the top of the inheritance graph, that
change affects all members of the
hierarchy.
Extension Point: Interface Inheritance
Interfaces are better extension points because they can be decorated with rich object graphs of functionality
Object graphs of functionality touch upon many different contexts.
Object graphs are more flexible than classes.
The writer’s point of view (Gary McLean Hall- Adaptive Code:Agilecoding with design patterns and SOLID principles):
«I don’t mean that the virtual and abstract methods that form the
extension points of class inheritance are not useful, but that they do not provide quite the same level of adaptability as do interfaces»
“Design for Inheritance or Prohibit it”
In his book Effective Java (Addison-Wesley, 2008), Joshua Bloch has this to say about inheritance:
Design and document for inheritance or else prohibit it.
If you choose to use implementation inheritance as an extension point, you must design and document the class properly so as to protect and inform future programmers who extend the class.
Inheritance of classes can be tricky
New subclasses can break existing code in unpredictable ways.
OCP Principle: Protected Variation
«Identify points of predicted variation and create a stable interface
around them».
Alistair Cockburn, Pattern Languages of Program Design, vol. 2 , 1996)
The requirements of an individual class should be linked directly to a business client’s requirement.
If this link is ignored, there is a risk that the class will not serve any purpose that the business client requested.
In fact, user stories are taken from the sprint backlog, and developers and the product ownerHere, questions should be asked as to the potential for future, related
requirements.
This informs the predicted variation that can be translated into extension points.
The Liskov Substitution Principle (LSP)
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
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.
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.
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 RulesThe LSP rules can be split into two categories
Contract rules (relating to the expectations of classes)
Variance rules (relating to the types that can be substituted in code)
Contract Rules
LSP Rules
Preconditions cannot be strengthened in a subtype
you cannot require more than the parent
Postconditions cannot be weakened in a subtype
You cannot guarantee less than the parent
Invariants of the supertype must be preserved in a subtype.
Interface Contracts
Contravariant
Covariant
Invariant
covariance is a relationship where subtypes go with each other,
contravariance is a relationship where subtypes go against each other.
When we talk about covariance and contravariance then subtypes and supertypes comes first in discussion.Subtypes can substitute for Supertypes.
CovarianceWhen function return values can changed to subtypes, covariance is
moving down the hierarchy.
class Product {
func calculateShippingCost() -> BaseShippingStrategy {
return BaseShippingStrategy()
} }
class PhoneProduct: Product {
// An instance of a subclass can always be substituted for an instance of
its superclass.
override func calculateShippingCost() -> WorldShippingStrategy {
return WorldShippingStrategy()
} }
ContravarianceWhen function parameters can be changed to supertypes, contravariance is
moving up the hierarchy.
On modifying parameter type to subtype down the hierarchy, we get Method doesn't override error
class Product {
func order(strategy:
WorldShippingStrategy) {
} }
class PhoneProduct: Product {
override func order(strategy:
BaseShippingStrategy) {
} }
FINALLY with No LLP Rule
Protocol LoginUseCase define method to be implemented by class.
Client who consumes use case should be able to work with both
DefaultLoginUseCase , MockLoginUseCase without any change in code.