design principles - solid

Post on 16-Apr-2017

60 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Design PrinciplesPranalee Rokde

WHY?• Difficult to understand 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

SYMPTOMS OF BAD DESIGN• Rigidity

• Fragility

• Immobility

• Viscosity

RIGIDITY• It is hard to change because every change affects too many

other parts of the system.

FRAGILITY• When you make a change, unexpected parts of the system

break.

IMMOBILITY• Inability to reuse 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.

VISCOSITY•  When the hacks are easy to employ than the design

preserving methods

SOLID• Single Responsibility Principle

• Open Closed Principle

• Liskov's Substitution Principle

• Interface Segregation Principle

• Dependency Inversion Principle

SRP – SINGLE RESPONSIBILITY 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

public class Employee {public Money calculatePay() ...

public String reportHours() ...

public void save() ...}

SINGLE RESPONSIBILITY PRINCIPLE

public class Employee { public Money calculatePay() ...

}

public class EmployeeReporter { public String reportHours(Employee e) ...

}

public class EmployeeRepository { public void save(Employee e) ...

}

Single Responsibility Principlepublic class UserSettingService{ public void changeEmail(User user) { if(checkAccess(user)) { //Grant option to change } } public boolean checkAccess(User user) { //Verify if the user is valid. }}

Single Responsibility Principlepublic class 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 } }}

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

OCP - OPEN CLOSED PRINCIPLE • Software entities should be open for extension but closed for

modification

OCP - Example Version 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; } }

OCP - Example Version 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; } }

OCP - Example Version 3public 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; }}

OCP• OCP is heart of object oriented design

• OCP leads to design patterns like Factory, Observer

SRP/OCP Benefits• Less merge 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

LSP - LIKOV'S SUBSTITUTION PRINCIPLE• Child classes should never break the parent class' type

definitions

LSP - LIKOV'S SUBSTITUTION PRINCIPLEclass 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;

}

}

LSP - LIKOV'S SUBSTITUTION PRINCIPLEclass 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.

}}

LSP - LIKOV'S SUBSTITUTION PRINCIPLE• LSP must be followed correctly in order for OCP to function

correctly

ISP - INTERFACE SEGREGATION PRINCIPLE

• Fat interfaces

• No clients should be forced to implement methods it doesn't use.

• Abstract class - sub classes with doNothing override

ISP - Violation Exampleinterface IMessage {

List<String> getToAddresses();

String getMessageBody();

String getSubject();

boolean Send();}

ISP - Violation Exampleclass EmailMessage implements IMessage {

public List<String> getToAddresses() {// return addressesreturn null;

}public String getMessageBody() {

// return message bodyreturn null;

}public String getSubject() {

// return subjectreturn null;

}public boolean Send() {

// send emailreturn false;

}}

class SMSMessage implements IMessage {public List<String> getToAddresses() {

// return addressesreturn null;

}public String getMessageBody() {

// return message bodyreturn null;

}public String getSubject() {

throw new RuntimeException("SMS don't have subject");}public boolean Send() {

// send smsreturn false;

}

}

ISP Exampleinterface IMessage {

List<String> getToAddresses();

String getMessageBody();

boolean Send();}

interface IEmailMessage extends IMessage{List<String> getBccAddresses();String getSubject();

}

ISP Exampleclass EmailMessage implements IEmailMessage {

public List<String> getToAddresses() {// return addressesreturn null;

}public String getMessageBody() {

// return message bodyreturn null;

}public String getSubject() {

// return subjectreturn null;

}public boolean Send() {

// send emailreturn false;

}public List<String> getBccAddresses() {

// return bcc addressesreturn null;

}}

class SMSMessage implements IMessage {public List<String> getToAddresses() {

// return addressesreturn null;

}public String getMessageBody() {

// return message bodyreturn null;

}public boolean Send() {

// send smsreturn false;

}}

ISP• Fat interfaces lead to inadvertent couplings

DIP - DEPENDENCY INVERSION PRINCIPLEpublic class ElectricPowerSwitch { public LightBulb lightBulb; public boolean on; public ElectricPowerSwitch(LightBulb lightBulb) { this.lightBulb = lightBulb; this.on = false; } public boolean isOn() { return this.on; } public void press(){ boolean checkOn = isOn(); if (checkOn) { lightBulb.turnOff(); this.on = false; } else { lightBulb.turnOn(); this.on = true; } }}

public class LightBulb { public void turnOn() { System.out.println("LightBulb: Bulb turned on..."); } public void turnOff() { System.out.println("LightBulb: Bulb turned off..."); }}

DIP - DEPENDENCY INVERSION PRINCIPLEpublic interface Switch { boolean isOn(); void press();}

public class ElectricPowerSwitch implements Switch { public Switchable client; public boolean on; public ElectricPowerSwitch(Switchable client) { this.client = client; this.on = false; } public boolean isOn() { return this.on; } public void press(){ boolean checkOn = isOn(); if (checkOn) { client.turnOff(); this.on = false; } else { client.turnOn(); this.on = true; } }}

public interface Switchable { void turnOn(); void turnOff();}

public class LightBulb implements Switchable { @Override public void turnOn() { System.out.println("LightBulb: Bulb turned on..."); } @Override public void turnOff() { System.out.println("LightBulb: Bulb turned off..."); }}

DIP

Few more…• DRY/WET

• Abstract class

• Package principles

Thank YouReferences

• Articles by Robert Martin

top related