ood and solid principles

53
OOD AND SOLID PRINCIPLES

Upload: avinash-kadam

Post on 01-Jul-2015

278 views

Category:

Design


0 download

DESCRIPTION

Basics of object oriented design and in detail about SOLID principles.

TRANSCRIPT

Page 1: Ood and solid principles

OOD AND SOLID PRINCIPLES

Page 2: Ood and solid principles

Object Oriented Programming

“A m e tho d o f p ro g ra m m ing ba s e d o n a hie ra rchy o f c la s s e s , a nd we ll-d e fine d a nd c o o p e ra ting

o b je c ts . ”

Page 3: Ood and solid principles

Object Oriented Design

It’s a process of planning a software system where objects will interact with each other to solve specific problems. The saying goes, "Proper Object oriented design makes a developer's life easy, whereas bad design makes it a disaster."

Page 4: Ood and solid principles

How does anyone start?

When anyone starts creating software design, their intentions are good. They try to use their existing experience to create an elegant and clean design.

Page 5: Ood and solid principles

Where it heads?

Over time software starts to rot. With every feature request or change software design alters its shape and eventually the simplest changes to application requires a lot of effort and, more importantly, creates higher chances for more bugs.

Page 6: Ood and solid principles

Who is to Blame? Software solves real life business problems and since

business processes keep evolving, software keeps on changing.

Changes are an integral part of the software world. Obviously because clients are paying they will demand for what they are expecting. So we cannot blame "change" for the degradation of software design. It is our design which is at fault.

One of the biggest reasons for the damaging of software design is the introduction of unplanned dependencies into the system. Every part of the system is dependant on some other part and so changing one part will affect another part. If we are able to manage those dependencies we will easily maintain the software system and software quality too.

Page 7: Ood and solid principles

How comes to rescue?Principles, Design Patterns and Software architecture

Software architecture like MVC, 3-Tier, MVP tells us how overall projects are going to be structured.

Design pattern allows us to reuse the experience or rather, provides reusable solutions to commonly occurring problems. Example – an object creation problem, an instance management problem, etc.

Principles tell us, do these and you will achieve this. How you will do it is up to you. Everyone defines some principles in their lives like, "I never lie" or "I never drink …." etc. He/she follow these principles to make his/her life easy, but how will he/she stick to these principles is up to the individual.

Page 8: Ood and solid principles

SOLID

Page 9: Ood and solid principles

SOLID - What is SOLID?

For those who haven't heard about it, SOLID is acronym composed from principles names. (There are 5 of them.)

SOLID doesn't have any particular meaning. It's just a good way to remember list of principles.

These principles are about low-level design and partly interpretation of OOP basics.

Introduced by Robert C. Martins

Page 10: Ood and solid principles

SOLID SOLID

- Single Responsibility Principle- Open Closed Principle- Liskov Substitution Principle- Interface Segregation Principle- Dependency Inverison Principle

Code becomes more Te s ta ble (remember TDD is not only about testing, more important its about Design)

Apply ’smart’- don’t do stuff ’just because of’- very important to see the context of the program/code when applying SOLID

It’s said (Wikipedia) when all five principles are applied together intend to make it more likely that a programmer will create a system that is easy to maintain and extend over time. Let’s talk about every principle in detail

Page 11: Ood and solid principles

Single Responsibility Principle

"The re s ho uld ne ve r be m o re tha n o ne re a s o n fo r a c la s s to cha ng e . " — Ro be rt Ma rtin, SRP p a p e r linke d fro m The Princ ip le s o f O O D

Or

"A class should have one and only one responsibility"

Page 12: Ood and solid principles

SRP - Real world comparison

He works as a team leader for one of the software firm. In his spare time he do some writing, newspaper editing and other various projects. Basically, he has multiple responsibilities in his life.When something bad happens at her work place, like when his boss scolds him for some mistake, he get distracted from his other work. Basically, if one thing goes bad, everything will mess up.

Page 13: Ood and solid principles

SRP - Problem in Programming Two (Employee DB Operations and Report Generation)

different resposibilitiespublic class Employee {

public string EmployeeName { get; set; } public int EmployeeNo { get; set; } public void Insert(Employee e) { //Database Logic written here } public Employee Select() { //Database Logic written here }public void GenerateReport(Employee e) { //Set report formatting }

}

Every time insert logic changes, this class will change. Every time report format changes, this class will changes. Every time one gets changed there is a chance that the other

also gets changed because both are staying in the same home and both have same parent. So a single change leads to double testing (or maybe more).

Page 14: Ood and solid principles

Solutions which will not Violate SRPNow it’s up to us how we achieve this. One thing we can do is create three different

classes Employee – Contains Properties (Data) EmployeeDB – Does database operations EmplyeeReport – Does report related tasks

public class Employee {

public string EmployeeName { get; set; }

public int EmployeeNo { get; set; }

}

public class EmployeeDB {

public void Insert(Employee e) { //Database Logic written here }

public Employee Select() { //Database Logic written here }

} public class EmployeeReport {

public void GenerateReport(Employee e) { //Set report formatting } }

Page 15: Ood and solid principles

Solutions which will not Violate SRPNote: This principle also applies to methods. Every method should

have a single responsibility.Can a single class can have multiple methods? The answer is YES. Now you might ask how it’s possible that

A class will have single responsibility. A method will have single responsibility. A class may have more than one method.

Well the answer for this question is simple. It’s context. Here, responsibility is related to the context in which we are speaking. When we say class responsibility it will be somewhat at higher level. For instance, the EmployeeDB class will be responsible for employee operations related to the Database whereas the EmployeeReport class will be responsible for employee operations related to reports.

When it comes to methods it will be at lower level. For instance look at following example:

Page 16: Ood and solid principles

Solutions which will not Violate SRP//Me tho d with m ultip le re s p o ns ibilitie s – v io la ting

SRP public void Insert(Employee e) {

string StrConnectionString = "";

SqlConnection objCon = new SqlConnection(StrConnectionString);

SqlParameter[] SomeParameters=null;//Create Parameter array from values SqlCommand objCommand = new SqlCommand("InertQuery", objCon); objCommand.Parameters.AddRange(SomeParameters); ObjCommand.ExecuteNonQuery();

}

Page 17: Ood and solid principles

Solutions which will not Violate SRP//Method with single responsibility – follow SRP

public void Insert(Employee e) {

SqlConnection objCon = GetConnection();

SqlParameter[] SomeParameters=GetParameters();

SqlCommand ObjCommand = GetCommand(objCon,"InertQuery",SomeParameters); ObjCommand.ExecuteNonQuery();

}

private SqlCommand GetCommand(SqlConnection objCon, string InsertQuery, SqlParameter[] SomeParameters) {

SqlCommand objCommand = new SqlCommand(InsertQuery, objCon);

objCommand.Parameters.AddRange(SomeParameters); r

eturn objCommand;

}

private SqlParameter[] GetParaeters() {

//Create Paramter array from values

}

private SqlConnection GetConnection() {

string StrConnectionString = "";

return new SqlConnection(StrConnectionString);

}

Page 18: Ood and solid principles

Open Closed Principle "So ftwa re e ntitie s (c la s s e s , m o dule s , func tio ns , e tc . ) s ho uld

be o p e n fo r e x te ns io n, but c lo s e d fo r m o d ific a tio n. " — Ro be rt Ma rtin, O CP p a p e r linke d fro m The Princ ip le s o f O O D

Or, “Change a class’s behavior using inheritance and composition”

At the most basic level, that means, you should be able to extend a class's behavior without modifying it. It's just like I should be able to put on a dress without doing any change to my body,

So in OOD, open for extensions means that the behavior of the module/class can be extended and we can make the module behave in new and different ways as the requirements change, or to meet the needs of new applications.

Page 19: Ood and solid principles

OCP - Real World Comparison

Let’s assume you want to add one more floor between the first and second floor in your two floor house. Do you think it is possible? Yes it is, but is it feasible? Here are some options: One thing you could have done at time you were building the house first time was

make it with three floors, keeping second floor empty. Then utilize the second floor anytime you want. I don’t know how feasible that is, but it is one solution.

Break the current second floor and build two new floors, which is not sensible.

Page 20: Ood and solid principles

OCP - Identify Problem in Programming Let's say the Select method in the EmployeeDB class is used

by two clients/screens. One is made for normal employees, one is made for managers, and the Manager Screen needs a change in the method.

If I make changes in the Select method to satisfy the new requirement, other UI will also be affected. Plus making changes in existing tested solution may result in unexpected errors.

Page 21: Ood and solid principles

Solution which will not violate OCPWe will derive a new class called  EmployeeManagerDB from EmployeeDB and override the Select method as per the new requirement.

public class EmployeeDB { public virtual Employee Select() {

//O ld Se le c t Me tho d

}

}

public class EmployeeManagerDB extends EmployeeDB { public override Employee Select() {

//Se le c t m e tho d a s p e r Ma na g e r //UI re q uire m e nt

}

}

Page 22: Ood and solid principles

Example 2 – Violating Open-Close Principle // Open-Close Principle - Bad example

class GraphicEditor {

public void drawShape(Shape s) {if (s.m_type==1)

drawRectangle(s);else if (s.m_type==2)

drawCircle(s);}public void drawCircle(Circle r) {....}public void drawRectangle(Rectangle r) {....}

}

class Shape {int m_type;

}

class Rectangle extends Shape {Rectangle() {

super.m_type=1;}

}

class Circle extends Shape {Circle() {

super.m_type=2;}

}

Page 23: Ood and solid principles

Open Closed Principle

Few Problems Impossible to add a new Shape without modifying GraphEditor

Important to understand GraphEditor to add a new Shape

Tight coupling between GraphEditor and Shape

Difficult to test a specific Shape without involving GraphEditor

If-Else-/Case should be avoided

Page 24: Ood and solid principles

Open Closed Principle

Solution// Open-Close Principle - Good example

class GraphicEditor {public void drawShape(Shape s) {

s.draw();}

}

class Shape {abstract void draw();

}

class Rectangle extends Shape {public void draw() {// draw the rectangle}

}

Page 25: Ood and solid principles

When should we apply OCP

If we look back our previous example, where did we go wrong? Clearly even our first implementation wasn’t open for extension. Should it have been? I’d say that it all depends on context. If we had had very strong suspicions that {business} would ask us to support other shapes later on we could probably have prepared for that from word go. However, often it’s not a good idea to try to anticipate changes in requirements ahead of time and preparing for future changes which can easily lead to overly complex designs. Instead, we focus on writing code that is well written enough so that it’s easy to change if the requirements change.

Once the requirements do change though it’s quite likely that they will change in a similar way again later on. That is, if {business}asks us to support another type of shape it’s quite likely that {business} soon will ask for support for a third type of shape.

So, in other words, we should have put some effort into abiding by the open/closed principle once the requirements started changing. Before that, in most cases, I would suggest limiting your efforts to ensuring that the code is well written enough so that it’s easy to refactor if the requirements starts changing.

Page 26: Ood and solid principles

Liskov Substitution Principle

"Func tio ns tha t us e p o inte rs o r re fe re nc e s to ba s e c la s s e s m us t be a ble to us e o b je c ts o f d e rive d c la s s e s witho ut kno wing it. " — Ro be rt Ma rtin, LSP p a p e r linke d fro m The Princ ip le s o f O O D

Mean, subclasses should behave nicely when used in place of their base class

Page 27: Ood and solid principles

LSP - Real World Comparison

A father is a real estate business man whereas his son wants to be cricketer.

A son can’t replace his father in spite of the fact that they belong to same family hierarchy. 

In basic Object Oriented Principles, "Inheritance" is usually described as an "is a" relationship. If a "Developer" is a "SoftwareProfessional", then the "Developer" class should inherit the "SoftwareProfessional" class. Such "Is a" relationships are very important in class designs, but it's easy to get carried away and end up in a wrong design with a bad inheritance.

The "Liskov's Substitution Principle" is just a way of ensuring that inheritance is used correctly.

Page 28: Ood and solid principles

LSP – Problem in programmingWe have an interface defined likePublic interface IPersistedResources{

void load();

void persist();

}

Interface that represents resources that can be loaded in memory, and persisted afterwards in case there were changes to it.

Let’s pretend we have the following implementations of that interface1)

Public class ApplicationSetting implemets IPersistedResources{

void load(){

//load application settings

}

void persist(){

//persist application settings

}

}

Page 29: Ood and solid principles

LSP – Problem in programming2)

Public class UserSetting implemets IPersistedResources{

void load(){

//load User settings

}

void persist(){

//persist User settings

}

}

Page 30: Ood and solid principles

LSP – Problem in programmingSomewhere in the application we have some way to retrieve a list of instances of implementations of that interface, kind of like this:

Static List<IPersistedResources> loadAll(){List<IPersistedResources> resources = new ArrayList<>(){

new ApplicationSeetting();new UserSetting();

}for(IPersistedResources resource: resources){ resource.load();

}Return resources;

}Static saveAll(List<IPersistedResources> resources ){

for(IPersistedResources resource: resources){ resource.save();

}

}

And somewhere else we may use those methods

Page 31: Ood and solid principles

LSP – Problem in programmingEverything works great, until a new class is added to the system in order to handle, let’s say, some “special settings”:

3)

Public class SpecialSetting implemets IPersistedResources{

void load(){

//load User settings

}

void persist(){

throw new NotImplementedException();

}

}

It looks like the Load method does whatever stuff it’s supposed to do in order to handle loading these special settings. The Persist method, on the other hand, throws a NotImplementedException. As it turns out, those settings are meant to be read-only, therefore, the Persist method can’t really do anything.

Page 32: Ood and solid principles

LSP – Problem in programmingThe system is told to load the new class along with the other ones that implement that same

interfaceStatic List<IPersistedResources> loadAll(){

List<IPersistedResources> resources = new ArrayList<>(){

new ApplicationSeetting();

new UserSetting();

new SpecialSetting();

}

for(IPersistedResources resource: resources){

resource.load();

}

Return resources;

}

Now when we run the app everything should still work fine, until we hit the code that tries to persist all of those loaded resources, at which point we get a big and fat “NotImplementedException”.One (horrible) way to address this would be to change the SaveAll method:

Page 33: Ood and solid principles

LSP – Problem in programmingStatic saveAll(List<IPersistedResources> resources ){

for(IPersistedResources resource: resources){if(resource instanceOf SpecialSetting){

//Do nothing}else{

resource.save();}

}} If the specific resource being processed is of type SpecialSettings, we skip that one. Brilliant! Well,

maybe not. Let’s look back at a simplified definition of the Liskov Substitution Principle: “An o bje c t s ho uld be s ubs tituta ble by its ba s e c la s s (o r inte rfa c e ). ” Looking at the SaveAll method it should be clear that “SpecialSettings” is NOT substitutable by its

“IPersistedResource” interface; if we call Persist on it, the app blows up, so we need change the method to take that one problem into consideration. One could say “we ll, le t’s cha ng e the Pe rs is t m e tho d o n tha t c la s s s o it wo n’t thro w a n e x c e p tio n a nym o re ”. Hmm, having a method on a class that when called won’t do what its name implies is just bad… really, really bad.

Write this down: anytime you see code that takes in some sort of baseclass or interface and then performs a check such as “if (someObject is SomeType)”, there’s a very good chance that that’s an LSP violation. I’ve done that, and I know so have you, let’s be honest.

Page 34: Ood and solid principles

LSP - SolutionThe fix here is to tailor the interface based on what each client needs (Interface Segregation Principle, or ISP). The LoadAll method (which is one client of those classes) is really only concerned about the “Load” capability, whereas the “SaveAll” method (another client) is only concerned about the “Persist” capability. In other words, these is what those clients need:

Static List<ILoadResources> loadAll(){List<ILoadResources> resources = new ArrayList<>(){

new ApplicationSeetting();new UserSetting();new SpecialSetting();

}for(ILoadResources resource: resources){ resource.load();

}Return resources;

}Static saveAll(List<ISaveResources> resources ){

for(ISaveResources resource: resources){ resource.save();

}

}

Page 35: Ood and solid principles

LSP - SolutionThe SaveAll takes in something tailored to its needs, IPe rs is tRe s o urc e ’s, and the same goes for LoadAll, which only cares about ILo a dRe s o urc e ’s (in the real app, the actual instantiation of these classes happen somewhere else). This is what the granular new interfaces look like:

Public interface IPersistResources{

void persist();

}

Public interface ILoadResources{

void load();

}

public class TestCalss {public static void main(String[] args) {List<ILoadResource> loadResources = new ArrayList<>();loadResources.add(new UserSetting());loadResources.add(new SpecialSetting());LoadAll(loadResources); // Call to load resource List<IPersistResource> persistResources = new ArrayList<>();persistResources.add(new UserSetting());persistResources.add((IPersistResource) new SpecialSetting());SaveAll(persistResources);}

}

Page 36: Ood and solid principles

LSP - Conclusion Yes, it’s pretty much the former “IPersistedResource” split up

into two separate interfaces, tailored to their client needs. Both the UserSettings and ApplicationSettings classes can implement these two interfaces, whereas the SpecialSettings class would only implement ILo a dRe s o urc e ; this way, it isn’t forced to implement interface members it can’t handle.

Very often people ask what’s the most appropriate number of members in an interface. In the real world example I gave here, the original interface had only 2 members; one could say that was small enough, but as it turns out, it wasn’t. The IPersistedResource interface was doing too much (both loading *and* persisting stuff) based on the clients that use its implementers. In the end, two interfaces with a single method on them fit the bill a lot better. Inte rfa c e s with s ing le re s p o ns ibility? Yes, Single Responsibility Principle (SRP); as with design patterns, sometimes SOLID principles go hand in hand together.

Page 37: Ood and solid principles

Interface Segregation Principle

"Clie nts s ho uld no t be fo rc e d to d e p e nd up o n inte rfa c e s tha t the y d o no t us e . " — Ro be rt Ma rtin, ISP p a p e r linke d fro m The Princ ip le s o f O O D

Keep interfaces small

Page 38: Ood and solid principles

ISP – Real World Comparison

Let’s say you purchase a new desktop PC. You will find a couple of USB ports, some serial ports, a VGA port etc. If you open the cabinet you will see lots of slots on the motherboard used for connecting various parts with each other, mostly used by hardware engineers at the time of assembly.

Those internal slots will not be visible until you open the cabinet. In short, only the required interfaces are made available/visible to you. Imagine a situation where everything was external or internal. Then there is a greater chances of hardware failure (as if life wasn't hard enough for computer users).

Page 39: Ood and solid principles

ISP – Real World Comparison

Let’s say we will go to a shop to buy something (let’s say, for instance, to buy a cricket bat).

Now imagine a situation where the shopkeeper starts showing you the ball and stumps as well. It may be possible that we will get confused and may end up buying something we did not require. We may even forget why we were there in the first place.

Page 40: Ood and solid principles

ISP - Problem in Programming

Let’s say we want to develop a Report Management System. Now, the very first task is creating a business layer which will be used by three different UIs.

EmployeeUI – Show reports related to currently logged in employee

ManagerUI – Show reports related to himself and the team for which he/manager belongs.

AdminUI – Show reports related to individual employee ,related to team and related to company like profit report.

Page 41: Ood and solid principles

ISP - Problem in ProgrammingSuppose we have a report generation service in our application as follow,public interface IReportService {

void generatePFReport(); void generateESICReport(); void generateResourcePerformanceReport(); void generateProjectSchedule(); void generateProfitReport();

} public class ReportSericeImpl implements IReportServvice {

public void generatePFReport() {//} public void generateESICReport() {// }public void generateResourcePerformanceReport() {//}public void generateProjectSchedule() {//} public void generateProfitReport() {// }

}

Page 42: Ood and solid principles

ISP - Problem in Programmingpublic class EmployeeUI {

public void DisplayUI() { IReportSerice objBal = new ReportServiceImpl(); objBal.generateESICReport(); objBal.generatePFReport();

}} public class ManagerUI {

public void DisplayUI() { IReportSerice objBal = new ReportServiceImpl(); objBal.generateESICReport(); objBal.generatePFReport(); objBal.generateResourcePerformanceReport (); objBal.generateProjectSchedule ();

} }

Page 43: Ood and solid principles

ISP - Problem in Programming

public class AdminUI {

public void DisplayUI() { I

IReportSerice objBal = new ReportServiceImpl();

objBal.generateESICReport();

objBal.generatePFReport();

objBal.generateResourcePerformanceReport();

objBal.generateProjectSchedule();

objBal.generateProfitReport();

}

}

Page 44: Ood and solid principles

ISP - What is the problem?

The developer who is working on EmployeeUI gets access to all the other methods as well, which may unnecessarily cause him/her confusion.

Page 45: Ood and solid principles

ISP - Solution//Segregating the report service in to three specific report services

public interface IEmployeeReportService {

void GeneratePFReport();

void GenerateESICReport();

}

public interface IManagerReportService extends IEmployeeReportService {

void GenerateResourcePerformanceReport();

void GenerateProjectSchedule();

}

public interface IAdminReportService: IManagerReportService {

void GenerateProfitReport();

}

By following ISP we can make client see, what he is required to see.

Page 46: Ood and solid principles

Interface Segregation Principle

“Each collaboration of a class which violates SRP should be articulated through separate interface”

Don’t force classes so implement methods they can’t (Swing/Java)

Don’t pollute interfaces with a lot of methods Avoid ’fat’ interfaces

Page 47: Ood and solid principles

Dependency Inversion Principle "A. Hig h le ve l m o dule s s ho uld no t d e p e nd up o n lo w le ve l

m o dule s . Bo th s ho uld d e p e nd up o n a bs tra c tio ns .B. Abs tra c tio ns s ho uld no t d e p e nd up o n d e ta ils . De ta ils s ho uld d e p e nd up o n a bs tra c tio ns . " — Ro be rt Ma rtin, DIP p a p e r linke d fro m The Princ ip le s o f O O D

Translation: Use interfaces and abstractions Motivation is that if high-level code depends on low-level

code, you'll have to recompile, retest whole project every time low-level code changes. There is an implication that low-level code changes often. For example, it's totally ok to depend on java.lang.String class since its interface won't be broken in next JDK. But if you're in progress of writing your own library for communication with hardware (for example), it's better not to depend on its low-level details.

Page 48: Ood and solid principles

DIP: Real World Comparison

Would you solder the electrical lamp directly to wiring in wall? I think NO. Let’s talk about our desktop computers. Different parts such as RAM, a hard disk, and CD-ROM (etc.) are loosely connected

to the motherboard. That means that, if, in future in any part stops working it can easily be replaced with a new one.

Imagine a situation where all parts were tightly coupled to each other, which means it would not be possible to remove any part from the motherboard. Then in that case if the RAM stops working we have to buy new motherboard which is going to be very expensive.

Page 49: Ood and solid principles

DIP - Problem in ProgrammingLook at following code,

public class CustomerService implements ICutomerService { public void Insert(Customer c) {

try { //Insert logic } catch (Exception e) {

FileLogger f = new FileLogger(); f.LogError(e);

} }

} public class FileLogger {

public void LogError(Exception e) { //Log Error in a physical file }}

In the above code CustomerBAL is directly dependent on the FileLogger class which will log exceptions in physical file. Now let’s assume tomorrow we decides to log exceptions in the Event Viewer. Now what? Change existing code. Oh no! that might create a new error!

Page 50: Ood and solid principles

DIP : Solution

Create Logger Interface:public interface ILogger {

void LogError(Exception e);

}

//Log Error in a physical file

public class FileLogger implements ILogger {

public void LogError(Exception e) { // }

}

//Log Error in a physical file

public class EventViewerLogger implements ILogger {

public void LogError(Exception e) { //}

}

Page 51: Ood and solid principles

Time to yes thanks

So now we've covered all five principles of SOLID.

Thanks to Ro be rt Ma rtin .

Page 52: Ood and solid principles

Is it end?

NO, but we look into them in subsequent sessions. Following are other design principles which play vital role in software/application design: Program to Interface and abstraction Don't Repeat Yourself Encapsulate What Varies Hollywood Principle Apply Design Pattern wherever possible Strive for Loosely Coupled System Keep it Simple and Sweet / Stupid

Page 53: Ood and solid principles

ConclusionWe can’t avoid changes. The only thing we can do is develop and design software in such a way that it is able to handle such changes.

SRP should be kept in mind while creating any class, method or any other module (which even applies to SQL stored procedures and functions). It makes code more readable, robust, and testable. 

We can’t follow DIP each and every time, sometimes we have to depend on concrete classes. The only thing we have to do is understand the system, requirements and environment properly and find areas where DIP should be followed. 

Following DIP and SRP will opens a door to implement OCP as well. 

Make sure to create specific interfaces so that complexities and confusions will be kept away from end developers, and thus, the ISP will not get violated.

While using inheritance take care of LSP.