This document discusses design principles for writing maintainable code, including the SOLID principles. It describes symptoms of bad design like rigidity, fragility, immobility and viscosity. It then explains each SOLID principle in detail: single responsibility principle, open closed principle, Liskov substitution principle, interface segregation principle, and dependency inversion principle. For each principle, it provides examples of how to apply the principle correctly and the benefits it provides, such as making code easier to change and reuse.
WHY?
• Difficult tounderstand code
• Difficult to make safe changes, existing code gets change while
adding new feature as product expands
• Difficult to write jUnits
• Find 1 bug and have to search entire code base to fix for every
implementation
• Code review is difficult
IMMOBILITY
• Inability toreuse software from parts of the same project or from
other projects.
• It often happens that one engineer will discover that he needs a
module that is similar to one that another engineer wrote. However, it
also often happens that the module in question has too much
baggage that it depends upon.
• It is hard to reuse in another application because it cannot be
separated from the current application.
SOLID
• Single ResponsibilityPrinciple
• Open Closed Principle
• Liskov's Substitution Principle
• Interface Segregation Principle
• Dependency Inversion Principle
10.
SRP – SINGLERESPONSIBILITY PRINCIPLE
• A class should have only one responsibility.
• A class should have only one reason to change.
• If we have 2 reasons to change for a class, we have to split the
functionality in two classes.
SINGLE RESPONSIBILITY PRINCIPLE
publicclass Employee {
public Money calculatePay() ...
}
public class EmployeeReporter {
public String reportHours(Employee e) ...
}
public class EmployeeRepository {
public void save(Employee e) ...
}
13.
Single Responsibility Principle
publicclass UserSettingService
{
public void changeEmail(User user)
{
if(checkAccess(user))
{
//Grant option to change
}
}
public boolean checkAccess(User user)
{
//Verify if the user is valid.
}
}
14.
Single Responsibility Principle
publicclass SecurityService
{
public static boolean checkAccess(User user)
{
//check the access.
}
}
public class UserSettingService
{
public void changeEmail(User user)
{
if(SecurityService.checkAccess(user))
{
//Grant option to change
}
}
}
15.
Single Responsibility Principle
•The SRP is one of the simplest of the principles, and one of the
hardest to get right
• An axis of change is only an axis of change if the changes actually
occur.
• It is not wise to apply the SRP, or any other principle for that matter, if
there is no symptom
• i.e. Don’t fall into trap of needless complexity
16.
OCP - OPENCLOSED PRINCIPLE
• Software entities should be open for extension but closed for
modification
17.
OCP - ExampleVersion 1
public class AreaCalculator
{
public double Area(Rectangle[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
area += shape.Width*shape.Height;
}
return area;
}
}
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
}
18.
OCP - ExampleVersion 2
public double Area(object[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
if (shape is Rectangle)
{
Rectangle rectangle = (Rectangle) shape;
area += rectangle.Width*rectangle.Height;
}
else
{
Circle circle = (Circle)shape;
area += circle.Radius * circle.Radius * Math.PI;
}
}
return area;
}
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
}
public class Circle
{
public double Radius { get; set; }
}
19.
OCP - ExampleVersion 3
public double Area(Shape[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
area += shape.Area();
}
return area;
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area()
{
return Width*Height;
}
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area()
{
return Radius*Radius*Math.PI;
}
}
20.
OCP
• OCP isheart of object oriented design
• OCP leads to design patterns like Factory, Observer
22.
SRP/OCP Benefits
• Lessmerge conflicts
• Less changes to existing code means easy to trace bug in regression
testing
• Saved efforts on rewriting jUnits as existing code has less chances to
change
23.
LSP - LIKOV'SSUBSTITUTION PRINCIPLE
• Child classes should never break the parent class' type definitions
24.
LSP - LIKOV'SSUBSTITUTION PRINCIPLE
class Rectangle
{
protected int m_width;
protected int m_height;
public void setWidth(int width){
m_width = width;
}
public void setHeight(int height){
m_height = height;
}
public int getWidth(){
return m_width;
}
public int getHeight(){
return m_height;
}
public int getArea(){
return m_width * m_height;
}
}
class Square extends Rectangle
{
public void setWidth(int width){
m_width = width;
m_height = width;
}
public void setHeight(int height){
m_width = height;
m_height = height;
}
}
25.
LSP - LIKOV'SSUBSTITUTION PRINCIPLE
class LspTest
{
private static Rectangle getNewRectangle()
{
// it can be an object returned by some factory ...
return new Square();
}
public static void main (String args[])
{
Rectangle r = LspTest.getNewRectangle();
r.setWidth(5);
r.setHeight(10);
// user knows that r it's a rectangle.
// It assumes that he's able to set the width and height as for the base class
System.out.println(r.getArea());
// now he's surprised to see that the area is 100 instead of 50.
}
}
26.
LSP - LIKOV'SSUBSTITUTION PRINCIPLE
• LSP must be followed correctly in order for OCP to function correctly
28.
ISP - INTERFACESEGREGATION PRINCIPLE
• Fat interfaces
• No clients should be forced to implement methods it doesn't use.
• Abstract class - sub classes with doNothing override