Related
Object Oriented programming paradigm uses inheritance to model relationships between entities that follow Generalization-Specialization relationship. Here, a Base class is used to encapsulate the common (General) attributes and behavior of a set of entities and the Derived Classes extend the base class by adding additional attributes and/or adding/modifying existing behavior.
As someone new to Functional Programming, I need guidance on modeling such relationships in functional languages like F#.
e.g. what would be the best approach to model a simple situation like the following:
abstract class Tutorial {
private String topic;
abstract public void learn();
}
class VideoTutorial extends Tutorial {
private float duration;
public void learn () {
System.out.println ("Watch Video");
}
}
class PDFTutorial extends Tutorial {
private int pageCount;
public void learn () {
System.out.println ("Read PDF");
}
}
and then later use a collection of Tutorials and call learn to observe polymorphic behavior.
In the functional design, you think about things a bit differently, so the ideas will not map perfectly. Typically, functional design focuses more on data types that express the entities you are working with. In your case, you could define TutorialKind which is either video or PDF using a discriminated union and Tutorial would then be a record that consits of a kind and its topic:
type TutorialKind =
| VideoTutorial of duration:float
| PDFTutorial of pageCount:int
type Tutorial =
{ Kind : TutorialKind
Topic : string }
Note that this keeps just the data about tutorials. Any functionality can be implemented in functions that pattern match on the kind of the tutorial:
let learn tutorial =
match tutorial.Kind with
| VideoTutorial _ -> printfn "Watch video"
| PDFTutorial _ -> printfn "Read PDF"
Note that this is extensible in a different direction than the OO version. In OO, you can easily add new subclasses; here you can easily add new functions. In practice, functional people are usually happy with this change, but F# is a mixed language and if you need "OO-style extensibility", you can easily use interfaces.
I had a simple concept for a 2d game. Think of like a Final Fantasy / D&D setting. I was working in C# but it's more of a general single-inheritance OO issue. I'm just assuming there's a scheme where you can implement many interfaces but inherit only one class.
There are three types of entities in the game: players, villagers, and enemies. To clarify, there can be multiple players (AI) because some may join the party.
For actions:
Players can do combat and dialogue. Villagers can only use dialogue. Enemies can only do combat.
For state:
All entities have a position on the map.
Combatants always have current health, max health, etc.
Dialogue entities always have some specific greeting text, dialogue options, etc.
Player, Villager, and Enemy would be my concrete classes. It seems I want 2 interfaces: Combat and Dialogue, handling all the actions. So far so good - however, these entities share state in a way problematic for single inheritance. Based on my design, it seems I want
an abstract Entity class with a position on the map
abstract classes AbstractCombatant the other AbstractDialogue both inheriting from Entity. AbstractCombatant, for example, has the state for health, equipment, etc.
The problem here is that Player would want to inherit from both Combatant and Dialogue abstract classes. With single inheritance, I can't. And if I could, I would have the diamond inheritance problem from the Entity class. Even if I just had my concrete classes inherit Entity instead, that would be another multiple inheritance problem. And of course, if I totally took the Entity part out of the equation and just mapped entities to positions separately, I would still suffer from the problem with Player inheriting from two classes.
I couldn't come up with a single-inheritance design that doesn't duplicate implementation. What is the best way to set up a class/interface hierarchy for this scenario?
It is only natural that you want to have a class for each concept (player, enemy, villager, etc.) in your problem domain / business domain. The issue arises naturally when these concepts share common features. Consider this example:
class House : IHouse
{
public int StreetNumber { get; }
}
class Boat : IBoat
{
public double SpeedKnots { get; }
}
class HouseBoat : House, Boat // does not compile
{
}
The simplest way to get around this is using aggregation.
Balanced
Keep references to all underlying concepts and implement the appropriate interfaces to provide all the required functionality.
class HouseBoat : IHouse, IBoat // implementing both interfaces is ok
{
private House house;
private Boat boat;
int IHouse.StreetNumber { get { return this.house.StreetNumber; } }
double IBoat.SpeedKnots { get { return this.boat.SpeedKnots; } }
}
Biased
Derive from one of the concepts (the one which is more similar) and implement the interface for the other concept(s).
class HouseBoat : Boat, IHouse // is more like a Boat
{
private House house; // model for the house aspects
int IHouse.StreetNumber { get { return this.house.StreetNumber; } }
}
Further Reading
This is quite a common problem since it comes naturally as mentioned above and both Java and C# do not allow multiple inheritance. A simple google query with the right search terms will provide abundant material.
I want to implement a library for card games of all types. I found out that OOP would probably the best way to implement such a library. So I started with modelling of some classes for UI (which has concrete subclasses ConsoleUI, SDLUI, HTMLUI), Party (with the subclasses Player and Group), Card, CardAttribute, Turn, TurnCommand, CompoundTurnCommand. Those classes are as good as complete.
But now I detected that there are several different kinds of collections of cards. I thought to create an abstract class CardCollections with many subclasses:
CardCollection = abstract collection of CardCollections
Card = a single card
Hand = an indexed random access list. If you execute draw(index), all CardCollections after index are shifted left (like a linked list)
Tablet = an indexed random access list. If you execute draw(index), the CardCollections after index are not shifted, can contain gaps between cards (like an array/dictionary)
Pile = an LIFO collection (like a stack)
Stock = a FIFO collection (like a queue)
Row = a double-ended collection (like a deque)
Random = a non-indexed undordered collection (like a bag)
Because I want to follow common OOP design practises, like inheritance and polymorphism, I am looking for a proper model - and here the problem begins.
I started to create interfaces for all concrete classes:
ICard extends IHand and ITablet.
IHand extends IRandom and IRow.
ITablet extends ICardCollection.
IPile extends ICardCollection.
IStock extends ICardCollection.
IRow extends IPile and IStock.
IRandom extends ICardCollection.
But I am very unsure about the design because it requires many, many interfaces.
Is there a better and more proper way for this? Because the library should be independent of the programming language I don't expect concrete implementations.
This is certainly not an acceptable answer, and maybe even subjective, but ... too long for a comment, and maybe it encourages others to give more profound answers:
It's difficult to give design hints as long as the description is so vague in terms of programming language and intended usage. E.g. I'm not entirely sure whether you mentioned Card as one of several CardCollections - intuitively, a single Card is no collection of cards. Additonally, in your description, you talked about CardCollections where I had expected only a Card (e.g. "...all CardCollections after index are shifted..." - shouldn't this be "...all Cards after index are shifted..." ?)
However, I think the decision about the precise inheritance relationship mainly depends on the methods that these classes will contain, and how they are intended to be used. Given the limited information, my "generic" approach would roughly be the following:
Insert all methods that you'd expect in the respective class. A first guess:
CardCollection {
int size();
}
Hand {
Card draw(int index);
}
Tablet {
Card draw(int index);
}
Pile {
void putFront(Card card);
Card takeFront();
}
Stock {
void putEnd(Card card);
Card takeEnd();
}
Row {
void putFront(Card card);
Card takeFront();
void putEnd(Card card);
Card takeEnd();
}
Random {
???
}
Factor out common parts. This might be tricky. It already depends on whether the language of choice supports multiple inheritance or things like interfaces in Java. More importantly, it depends on whether the language supports non-public inheritance. For example, when you write class ExtendedClass extends BaseClass or class ExtendedClass implements BaseInterface in Java, then this is set in stone. Everybody who uses the API will rely on this inheritance, and it can never be changed after the first release. In contrast to C++, where you can write class ExtendedClass : private BaseClass and the user of the API will never know that you inherited from BaseClass. (I'm not familiar with Tcl, Smalltalk or Lua, so I can't say anything about that - and for sure, C++ is the best example for a not-so-easy-to-learn language ;-)).
Construct an inheritance hierarchy based on the common parts. This could for example be according to what you already described, e.g. Row extends Pile and Stock. Alternatively, you could classify the classes according to what they allow you to do, possibly in some abstract form that is possibly not even directly visible to the user:
// Private part:
FrontQueue {
void putFront(Card card);
Card takeFront();
}
EndQueue {
void putEnd(Card card);
Card takeEnd();
}
// Public part:
Pile extends FrontQueue {}
Stock extends EndQueue {}
Row extends FrontQueue, EndQueue {}
Of course, this once more depends on the language and the intended usage. One would also have to ask whether these classes should rather serve as a "facade", and the actual behavior should be implemented via composition instead of inheritance. An obvious example for a further questions is: Should every method that expects a Pile also accept a Row? Alternatives for the class design might also be considered. For example, instead of letting Row inherit from FrontQueue and EndQueue, one could declare
Row {
FrontQueue getFront();
EndQueue getEnd();
}
Again, these are just thoughts, and in the worst case, not answering your question, but instead raising new questions, but ... maybe the ones that you have to answer on the way to your goal anyhow.
your design has already been done a few times. except for card, all of your interfaces are very similar to collection, list, queue, stack, and deque. there are the java collections framework, the c# collections framework, and dart. you will probably come up with something similar.
i would suggest a spike using concrete implementations where everything extends collection, list, queue, stack, or deque then refactor out whatever interface hierarchy that you can find.
edit: i just noticed that you have: ICard extends IHand and ITablet. card is probably it's own interface. something like:
enum Type {poker, tarot, magic ... }
interface {
Type type();
Map<String,Object> attributeNameToAttributeValue();
}
you could have sub interfaces for card flavours like:
enum Suit { clubs, diamonds, hearts, spades }
enum Rank { deuce,trey,four,five,six,seven,eight,nine,ten,jack,queen,king,ace }
interface PokerCard extends Card {
Rank rank();
Suite suit();
}
I know this question's been asked before (e.g., What is the difference between the bridge pattern and the strategy pattern?).
However, could someone please explain, using clear-cut examples, what the difference is and in what sorts of cases one must be selected over the other? Less conceptual theory, more practical "real-life" scenarios would be appreciated.
The Bridge Pattern makes a distinction between an abstraction and an implementation in such a way that the two can vary independently. I will use the example from
Patterns in Java, Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML, Second Edition
You need to provide classes that access physical sensors such as found in scales, speed measuring devices etc. Each sensor produces a number but the number could mean different things. For the scale it could mean the weight and for the speed measuring device it may mean speed.
So you can start by creating a Sensor abstract class to represent the commonality between all sensors and various subclasses for the different types of sensors. This is a robust design allowing you to provide many more types of sensors in the future.
Now suppose that sensors are provided by different manufacturers. You will have to create a heirarchy of sensor classes for manufacturer X and another for manufacturer Y. The problem now is that the clients would need to know the difference between the manufacturers. And if you decide to support a third manufacturer...?
The solution is to provide the main abstraction heirarchy, ie. the Sensor abstract class and sub classes such as SpeedSensor and WeightSensor and so on. Then provide the interface (Bridge) that will exist between the abstraction and the implementation. So there will be a SensorInterface, WeightSensorInterface and SpeedSensorInterface, which dictates the interface that each concrete sensor class must provide. The abstraction does not know about the implementation, rather it knows about the interface. Finally, you can create an concreate implementation for each manufacturer. That is, XSensor, XWeightSensor and XSpeedSensor, YSensor, YSpeedSensor and YWeightSensor.
Clients depend only on the abstraction but any implementation could be plugged in. So in this setup, the abstraction could be changed without changing any of the concrete classes, and the implementation could be changed without worrying about the abstraction.
As you can see this describes a way to structure your classes.
The Strategy on the other hand is concerned with changing the behaviour of an object at run time. I like to use the example of a game with a character that possesses several different types of weapons. The character can attack but the behaviour of attack depends on the weapon that the character is holding at the time, and this cannot be known at compile time.
So you make the weapon behaviour pluggable and inject it into the character as needed. Hence a behavioral pattern.
These two patterns solve different problems. The strategy is concerned with making algorithms interchangeable while the Bridge is concerned with decoupling the abstraction from the inplementation so that you can provide multiple implementations for the same abstraction. That is, the bridge is concerned with entire structures.
Here are a few links that might be useful:
Bridge Pattern
Strategy Pattern
I can tell this is hard to explain. Many people who use it and understand it have a hard time explaining it to newbies.
For those like me who think in terms of analogies:
Strategy Pattern
So strategy is kind-of a one-dimensional concept. Think of a one-dimensional array of strategies to choose from.
Example 1: Plumber's tools
The strategy pattern is like a plumber who has various tools to get a pipe unclogged. The job is the same each time; it's to unclog the pipe. But the tool he chooses to get this done can vary depending on the situation. Maybe he'll try one and if that doesn't work he'll try another.
In this analogy, "unclog the pipe" is the method that will implement one of the strategies. Snake brush, power auger, and draino are the concrete strategies, and the plumber is the class containing the method (labeled "Context" in most diagrams).
Example 2: Multi-bit screwdriver
Or you could think of the interchangeable bits on a multi-bit screwdriver.
They are meant to be changed out at run-time to suit the job at hand, which is to screw something.
Bridge Pattern
So bridge is a two-dimensional concept. Think of one dimension (the rows) being the list of methods that need to be implemented, and the second dimension (the columns) being the Implementors who will implement each one of those methods.
Example 1: Apps and devices
The bridge pattern is like a person that has many ways that they can communicate (email, text, google voice, phone, skype) and many devices on with which they can communicate in these various ways - a PC, a tablet, and a smart phone.
The various ways to communicate (email, text, phone) would be the methods on an abstract interface, let's call it "CommunicationDevice". In this pattern, CommunicationDevice is the Implementor. Each device in this analogy (PC, tablet, smart phone) is the ConcreteImplementor that implements all these methods (email, text, phone).
Example 2: Odbc database drivers and odbc functions
Another ready example of bridge is the odbc or oledb database driver modules from Windows. They all implement the various methods on the same standard "database driver" interface, but they implement that interface in different ways. Even if you are using the same database, say Sql Server, there are still different drivers that can talk to Sql Server, albeit in different ways under the covers.
Example 3: Implementors (columns) implementing methods (rows)
Strategy pattern
This pattern lets the algorithm that executes vary independently from the clients that use it. i.e. Instead of having a fixed algorithm to exeucte for a given sitaution, it allows one among many algorithms to be selected on-the-fly at runtime. This involves removing an algorithm from its host class and putting it in a separate class.
For example, suppose one wants to travel from a city to another, then he has several choices: take a bus, hire a car, catch a train, etc. So each mode of transport selected would transpire into a separate algorithm to be executed. The mode of transport chosen will depend on various factors decided at runtime (cost, time, etc.). In other words, the strategy chosen to execute will be decided on-the-fly.
Another example, suppose one wants to implement a SortedList class(main controller) that Sorts based on a strategy. The strategy is the method that one uses to sort (like MergeSort, QuickSort).
Comparison with the Bridge pattern
The main difference (even though both patterns have the same UML) is that unlike the bridge pattern (which is a structural pattern), the strategy pattern is a behavioral pattern. Structural patterns suggest ways in which objects are composed or associated or inherited to forms larger objects i.e. they focus on object composition. While behavioral patterns deal with the algorithm or business logic (and not on the object creation itself) i.e. they focus on the collaboration between objects.
Note that most algorithms can be implementated as static or singleton classes required only single instance creation (i.e. new is not called for everytime a strategy is set).
A closer look at the implementation of the two patterns will reveal that in the bridge pattern one creates the concrete implementation of the object and then the call.
// Set implementation and call
// i.e. Returns (creates) the concrete implementation of the object,
// subsequently operation is called on the concrete implementation
ab.Implementor = new ConcreteImplementorA();
ab.Operation();
Whereas in the case of the strategy pattern, one will not use the concrete implementation of the algorithm directly, instead he will create the context in which the strategy should execute,
// Set the context with a strategy
// i.e. Sets the concrete strategy into the context, concrete implementation of the class not
// directly available as a data object (only the algorithm is available).
context = new Context (new ConcreteStrategyA());
context.contextInterface();
// Strategy can be reused instead of creating a new instance every time it is used.
// Sort example
MergeSort mergeSort = new MergeSort();
QuickSort quickSort = new QuickSort();
...
context = new Context (mergeSort);
context.Sort();
...
context = new Context (quickSort);
context.Sort();
...
context = new Context (mergeSort);
context.Sort();
The Bridge pattern tells how organize classes, the Strategy - how organize algorithms.
Difference between bridge and strategy pattern:
Bridge pattern gives us the ability to re implement, being running business structure as per our current situation , other side strategy pattern gives us ability to implement our various business strategy and encapsulate them and use them as per situation or at a time.
Main difference between both is using bridge pattern we can change our whole structure but using strategy we are able to change our business strategy parallelly.
I have elaborated two very important design patter below as per my understanding.
please carefully go throw this i think it will clear your understanding about both them.
Bridge Pattern:
What is Bridge Design Pattern?
The sense of GoF suggested Bridge pattern is decouple the implementation of an component from it's abstraction.
When we will use the Bridge Design Pattern?
Let imagine a situation where a component already implemented, and it's running well as per your business need. Suddenly the organisation changed their business strategy. For this you need to be change or re-implemented the component. At this situation, what you will do change the previous one that are running well last few years, or you Create the new component. At this situation bridge pattern beautifully handled the scenario. See the example below for better understanding.
// Main component
public interface Ibridge
{
void function1();
}
// Already Implemented that are currently being using
public class Bridge1 : Ibridge
{
public void function1()
{
Console.WriteLine("Implemented function from bridge 1");
}
}
//New Implementation as per Organisation needs
public class Bridge2 : Ibridge
{
public void function1()
{
Console.WriteLine("Implemented function from bridge2");
}
}
//Abstract Calling functionalities
public interface IAbstractBridge
{
void CallFunc1();
}
// implementation of calling implemented component at a time
public class AbstractBridge:IAbstractBridge
{
protected Ibridge _ibridge;
public Ibridge Ibridge
{
set { _ibridge = value; }
}
public void CallFunc1()
{
this._ibridge.function1();
}
}
class Program
{
static void Main(string[] args)
{
AbstractBridge abp = new AbstractBridge();
/*
here you see that now being using the previous implemented component.
but need change newly implemented component so here we need just changed
the implementation of component, please see below
*/
//Commented old one
abp.Ibridge = new Bridge1();
//using new one just change the "Bridge1" to "Bridge2"
abp.Ibridge = new Bridge2();
abp.CallFunc1();
}
}
Strategy design Pattern:
What is Strategy Design Pattern?
The sense of GoF suggested Strategy pattern is Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
When we will use the Strategy Design Pattern?
Let imagine a situation where a owner of shopping complex want to attract customer giving different discount offer based on their various occasion and the discount offer any time owner can switch from discount mode to normal mode vice versa ,then how to handle this situation At this situation strategy pattern handled the scenario. Lets See the example below for better understanding.
All Strategy:
public interface ISellingStrategy
{
void selling();
}
public class BasicStrategy : ISellingStrategy
{
public void selling()
{
Console.WriteLine("Buy Three get 5% discount.");
}
}
public class ChrismasStrategy : ISellingStrategy
{
public void selling()
{
Console.WriteLine("Buy Three get one offer + extra 5% discount.");
}
}
public class HoliFestiveStrategy : ISellingStrategy
{
public void selling()
{
Console.WriteLine("Buy two get one offer + extra 5% discount.");
}
}
public class DurgapuljaStrategy : ISellingStrategy
{
public void selling()
{
Console.WriteLine("Buy one get one offer + extra 5% discount.");
}
}
Billing:
public class Billing
{
private ISellingStrategy strategy;
public void SetStrategy(ISellingStrategy _strategy)
{
this.strategy = _strategy;
}
public void ApplyStrategy()
{
strategy.selling();
Console.WriteLine("Please wait offer is being applying...");
Console.WriteLine("Offer is now Applied and ready for billing..");
}
}
Factory patter for Creating Object of Billing Class
public class BillingFactory
{
public static Billing CreateBillingObject()
{
return new Billing();
}
}
Calling
class Program
{
static void Main(string[] args)
{
Billing billing = BillingFactory.CreateBillingObject();
billing.SetStrategy(new BasicStrategy());
billing.ApplyStrategy();
Console.ReadLine();
}
}
Both patterns separate interface from implementation. I think the key distinction is that the Bridge Pattern uses inheritance ("is a") while the Strategy Pattern uses composition ("has a").
Bridge Pattern:
class Sorter abstract
{
virtual void Sort() = 0;
}
// MergeSorter IS A Sorter
class MergeSorter : public Sorter
{
virtual void Sort() override;
}
Strategy Pattern:
class SortStrategy abstract
{
virtual void Sort() = 0;
}
// Sorter HAS A SortStrategy
class Sorter
{
Sorter(SortStragety *strategy) : mStrat(strategy) {}
void Sort() {mStrat->Sort();}
SortStrategy *mStrat;
}
The Strategy pattern encapsulates algorithms so that they can be used and changed in a complex program (without gumming up the works) and the Bridge pattern allows two interfaces loosely bound so that they can interact but be changed independently of one another.
You can find PHP examples of the Bridge and Strategy patterns here:
http://www.php5dp.com/category/design-patterns/bridge/
and
http://www.php5dp.com/category/design-patterns/strategy/
You'll find a lot of examples for both patterns that may be helpful.
Strategy:
Strategy is behavioral design pattern. If is used to switch between family of algorithms.
This pattern contains one abstract strategy interface and many concrete strategy implementations (algorithms) of that interface.
The application uses strategy interface only. Depending in some configuration parameter, the concrete strategy will be tagged to interface.
Bridge:
It allows both abstractions and implementations to vary independently.
It uses composition over inheritance.
Bridge is a structural pattern.
However, could someone please explain, using clear-cut examples, what the difference is and in what sorts of cases one must be selected over the other?
Refer to below post to get insight on use cases of Strategy and Bridge patterns:
Real World Example of the Strategy Pattern
When do you use the Bridge Pattern? How is it different from Adapter pattern?
On quick note:
Use Strategy pattern to dynamically change the implementation by replacing one strategy with other strategy.
One real word example : Airlines offering discounts during off-peak months. Simply change fare discount strategy with no-discount strategy during high peak time.
Use Bridge pattern when Abstractions and implementations have not been decided at compile time and can vary independently
One real world example in Automobile industry : Different type of Gears can be assembled into different types of Cars. Both Car and Gear specification and implementation can change independently.
Let me recite the answers from the linked question.
The bridge pattern is a structural pattern, that is, it lays out ideas of how to build a component of your project. It is used to hide two levels of abstractions. The sample code on Wikipedia (http://en.wikipedia.org/wiki/Bridge_pattern) explains it in most unambiguous terms.
The strategy pattern is a dynamic pattern. When any wild function can implement the requirements, a strategy pattern is used. Examples can be any program that allows for plugins to be developed and installed. On the Wikipedia pageg(http://en.wikipedia.org/wiki/Strategy_pattern), ConcreteStrategyAdd, ConcreteStrategySubtract, etc is plugin used in the ConcreteStrategy class. Any method could be used there that implements the interface Strategy.
The Open/Closed Principle states that software entities (classes, modules, etc.) should be open for extension, but closed for modification. What does this mean, and why is it an important principle of good object-oriented design?
It means that you should put new code in new classes/modules. Existing code should be modified only for bug fixing. New classes can reuse existing code via inheritance.
Open/closed principle is intended to mitigate risk when introducing new functionality. Since you don't modify existing code you can be assured that it wouldn't be broken. It reduces maintenance cost and increases product stability.
Specifically, it is about a "Holy Grail" of design in OOP of making an entity extensible enough (through its individual design or through its participation in the architecture) to support future unforseen changes without rewriting its code (and sometimes even without re-compiling **).
Some ways to do this include Polymorphism/Inheritance, Composition, Inversion of Control (a.k.a. DIP), Aspect-Oriented Programming, Patterns such as Strategy, Visitor, Template Method, and many other principles, patterns, and techniques of OOAD.
** See the 6 "package principles", REP, CCP, CRP, ADP, SDP, SAP
More specifically than DaveK, it usually means that if you want to add additional functionality, or change the functionality of a class, create a subclass instead of changing the original. This way, anyone using the parent class does not have to worry about it changing later on. Basically, it's all about backwards compatibility.
Another really important principle of object-oriented design is loose coupling through a method interface. If the change you want to make does not affect the existing interface, it really is pretty safe to change. For example, to make an algorithm more efficient. Object-oriented principles need to be tempered by common sense too :)
Open Closed Principle is very important in object oriented programming and it's one of the SOLID principles.
As per this, a class should be open for extension and closed for
modification. Let us understand why.
class Rectangle {
public int width;
public int lenth;
}
class Circle {
public int radius;
}
class AreaService {
public int areaForRectangle(Rectangle rectangle) {
return rectangle.width * rectangle.lenth;
}
public int areaForCircle(Circle circle) {
return (22 / 7) * circle.radius * circle.radius;
}
}
If you look at the above design, we can clearly observe that it's not
following Open/Closed Principle. Whenever there is a new
shape(Tiangle, Square etc.), AreaService has to be modified.
With Open/Closed Principle:
interface Shape{
int area();
}
class Rectangle implements Shape{
public int width;
public int lenth;
#Override
public int area() {
return lenth * width;
}
}
class Cirle implements Shape{
public int radius;
#Override
public int area() {
return (22/7) * radius * radius;
}
}
class AreaService {
int area(Shape shape) {
return shape.area();
}
}
Whenever there is new shape like Triangle, Square etc. you can easily
accommodate the new shapes without modifying existing classes. With
this design, we can ensure that existing code doesn't impact.
Software entities should be open for extension but closed for modification
That means any class or module should be written in a way that it can be used as is, can be extended, but neve modified
Bad Example in Javascript
var juiceTypes = ['Mango','Apple','Lemon'];
function juiceMaker(type){
if(juiceTypes.indexOf(type)!=-1)
console.log('Here is your juice, Have a nice day');
else
console.log('sorry, Error happned');
}
exports.makeJuice = juiceMaker;
Now if you want to add Another Juice type, you have to edit the module itself, By this way, we are breaking OCP .
Good Example in Javascript
var juiceTypes = [];
function juiceMaker(type){
if(juiceTypes.indexOf(type)!=-1)
console.log('Here is your juice, Have a nice day');
else
console.log('sorry, Error happned');
}
function addType(typeName){
if(juiceTypes.indexOf(typeName)==-1)
juiceTypes.push(typeName);
}
function removeType(typeName){
let index = juiceTypes.indexOf(typeName)
if(index!==-1)
juiceTypes.splice(index,1);
}
exports.makeJuice = juiceMaker;
exports.addType = addType;
exports.removeType = removeType;
Now, you can add new juice types from outside the module without editing the same module.
Let's break down the question in three parts to make it easier to understand the various concepts.
Reasoning Behind Open-Closed Principle
Consider an example in the code below. Different vehicles are serviced in a different manner. So, we have different classes for Bike and Car because the strategy to service a Bike is different from the strategy to service a Car. The Garage class accepts various kinds of vehicles for servicing.
Problem of Rigidity
Observe the code and see how the Garage class shows the signs of rigidity when it comes to introducing a new functionality:
class Bike {
public void service() {
System.out.println("Bike servicing strategy performed.");
}
}
class Car {
public void service() {
System.out.println("Car servicing strategy performed.");
}
}
class Garage {
public void serviceBike(Bike bike) {
bike.service();
}
public void serviceCar(Car car) {
car.service();
}
}
As you may have noticed, whenever some new vehicle like Truck or Bus is to be serviced, the Garage will need to be modified to define some new methods like serviceTruck() and serviceBus(). That means the Garage class must know every possible vehicle like Bike, Car, Bus, Truck and so on. So, it violates the open-closed principle by being open for modification. Also it's not open for extension because to extend the new functionality, we need to modify the class.
Meaning Behind Open-Closed Principle
Abstraction
To solve the problem of rigidity in the code above we can use the open-closed principle. That means we need to make the Garage class dumb by taking away the implementation details of servicing of every vehicle that it knows. In other words we should abstract the implementation details of the servicing strategy for each concrete type like Bike and Car.
To abstract the implementation details of the servicing strategies for various types of vehicles we use an interface called Vehicle and have an abstract method service() in it.
Polymorphism
At the same time, we also want the Garage class to accept many forms of the vehicle, like Bus, Truck and so on, not just Bike and Car. To do that, the open-closed principle uses polymorphism (many forms).
For the Garage class to accept many forms of the Vehicle, we change the signature of its method to service(Vehicle vehicle) { } to accept the interface Vehicle instead of the actual implementation like Bike, Car etc. We also remove the multiple methods from the class as just one method will accept many forms.
interface Vehicle {
void service();
}
class Bike implements Vehicle {
#Override
public void service() {
System.out.println("Bike servicing strategy performed.");
}
}
class Car implements Vehicle {
#Override
public void service() {
System.out.println("Car servicing strategy performed.");
}
}
class Garage {
public void service(Vehicle vehicle) {
vehicle.service();
}
}
Importance of Open-Closed Principle
Closed for modification
As you can see in the code above, now the Garage class has become closed for modification because now it doesn't know about the implementation details of servicing strategies for various types of vehicles and can accept any type of new Vehicle. We just have to extend the new vehicle from the Vehicle interface and send it to the Garage. That's it! We don't need to change any code in the Garage class.
Another entity that's closed for modification is our Vehicle interface.
We don't have to change the interface to extend the functionality of our software.
Open for extension
The Garage class now becomes open for extension in the context that it will support the new types of Vehicle, without the need for modifying.
Our Vehicle interface is open for extension because to introduce any new vehicle, we can extend from the Vehicle interface and provide a new implementation with a strategy for servicing that particular vehicle.
Strategy Design Pattern
Did you notice that I used the word strategy multiple times? That's because this is also an example of the Strategy Design Pattern. We can implement different strategies for servicing different types of Vehicles by extending it. For example, servicing a Truck has a different strategy from the strategy of servicing a Bus. So we implement these strategies inside the different derived classes.
The strategy pattern allows our software to be flexible as the requirements change over time. Whenever the client changes their strategy, just derive a new class for it and provide it to the existing component, no need to change other stuff! The open-closed principle plays an important role in implementing this pattern.
That's it! Hope that helps.
It's the answer to the fragile base class problem, which says that seemingly innocent modifications to base classes may have unintended consequences to inheritors that depended on the previous behavior. So you have to be careful to encapsulate what you don't want relied upon so that the derived classes will obey the contracts defined by the base class. And once inheritors exist, you have to be really careful with what you change in the base class.
Purpose of the Open closed Principle in SOLID Principles is to
reduce the cost of a business change requirement.
reduce testing of existing code.
Open Closed Principle states that we should try not to alter existing
code while adding new functionalities. It basically means that
existing code should be open for extension and closed for
modification(unless there is a bug in existing code). Altering existing code while adding new functionalities requires existing features to be tested again.
Let me explain this by taking AppLogger util class.
Let's say we have a requirement to log application wide errors to a online tool called Firebase. So we create below class and use it in 1000s of places to log API errors, out of memory errors etc.
open class AppLogger {
open fun logError(message: String) {
// reporting error to Firebase
FirebaseAnalytics.logException(message)
}
}
Let's say after sometime, we add Payment Feature to the app and there is a new requirement which states that only for Payment related errors we have to use a new reporting tool called Instabug and also continue reporting errors to Firebase just like before for all features including Payment.
Now we can achieve this by putting an if else condition inside our existing method
fun logError(message: String, origin: String) {
if (origin == "Payment") {
//report to both Firebase and Instabug
FirebaseAnalytics.logException(message)
InstaBug.logException(message)
} else {
// otherwise report only to Firebase
FirebaseAnalytics.logException(message)
}
}
Problem with this approach is that it violates Single Responsibility Principle which states that a method should do only one thing. Another way of putting it is a method should have only one reason to change. With this approach there are two reasons for this method to change (if & else blocks).
A better approach would be to create a new Logger class by inheriting the existing Logger class like below.
class InstaBugLogger : AppLogger() {
override fun logError(message: String) {
super.logError(message) // This uses AppLogger.logError to report to Firebase.
InstaBug.logException(message) //Reporting to Instabug
}
}
Now all we have to do is use InstaBugLogger.logError() in Payment features to log errors to both Instabug and Firebase. This way we reduce/isolate the testing of new error reporting requirement to only Payment feature as code changes are done only in Payment Feature. The rest of the application features need not be tested as there are no code changes done to the existing Logger.
The principle means that it should easy to add new functionality without having to change existing, stable, and tested functionality, saving both time and money.
Often, polymorhism, for instance using interfaces, is a good tool for achieving this.
An additional rule of thumb for conforming to OCP is to make base classes abstract with respect to functionality provided by derived classes. Or as Scott Meyers says 'Make Non-leaf classes abstract'.
This means having unimplemented methods in the base class and only implement these methods in classes which themselves have no sub classes. Then the client of the base class cannot rely on a particular implementation in the base class since there is none.
I just want to emphasize that "Open/Closed", even though being obviously useful in OO programming, is a healthy method to use in all aspects of development. For instance, in my own experience it's a great painkiller to use "Open/Closed" as much as possible when working with plain C.
/Robert
This means that the OO software should be built upon, but not changed intrinsically. This is good because it ensures reliable, predictable performance from the base classes.
I was recently given an additional idea of what this principle entails: that the Open-Closed Principle describes at once a way of writing code, as well as an end-result of writing code in a resilient way.
I like to think of Open/Closed split up in two closely-related parts:
Code that is Open to change can either change its behavior to correctly handle its inputs, or requires minimum modification to provide for new usage scenarios.
Code that is Closed for modification does not require much if any human intervention to handle new usage scenarios. The need simply does not exist.
Thus, code that exhibits Open/Closed behavior (or, if you prefer, fulfills the Open/Closed Principle) requires minimal or no modification in response to usage scenarios beyond what it was originally built for.
As far as implementation is concerned? I find that the commonly-stated interpretation, "Open/Closed refers to code being polymorphic!" to be at best an incomplete statement. Polymorphism in code is one tool to achieve this sort of behavior; Inheritance, Implementation...really, every object-oriented design principle is necessary to write code that is resilient in the way implied by this principle.
In Design principle, SOLID – the "O" in "SOLID" stands for the open/closed principle.
Open Closed principle is a design principle which says that a class, modules and functions should be open for extension but closed for modification.
This principle states that the design and writing of the code should be done in a way that new functionality should be added with minimum changes in the existing code (tested code). The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged.
Benefit of Open Closed Design Principle:
Application will be more robust because we are not changing already tested class.
Flexible because we can easily accommodate new requirements.
Easy to test and less error prone.
My blog post on this:
http://javaexplorer03.blogspot.in/2016/12/open-closed-design-principle.html