Upload
pranalee-rokde
View
61
Download
2
Embed Size (px)
Citation preview
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