High Cohesion Low Coupling Old Standards for Object Oriented Programming

Preview:

Citation preview

High Cohesion

Low Coupling

Old Standards for Object Oriented Programming

Problems SolvedMaintainabilityEasier to TestLess Resistance to Change

Fear to Change Code Leads to Old Stinky CodeReduces Repetition (DRY)

Don’t Cut and Paste!!!!Allows For Continuous ImprovementEssential for Agile Development

Topics To DiscussSingle Responsibility PrincipleDependency Inversion PrincipleOpen Closed PrincipleInterface Segregation PrincipleLaw of DemeterLiskov Substitution Principle

Open Closed PrincipleClasses should be Open to Extensibility and

Closed to ModificationsTo Change behavior, you want to add new code

instead of modifying existing Code.May not have access to code

Single Responsibility PrincipleWhat is Responsibility?- Reason for change- Find how many reason you can think

of for you class/method to change- If more than one, then your design

violates SRP

Single Responsibility Principle

Demo

Single Responsibility PrincipleProblem:-we have more than one responsibility

reading transaction recordFormattingSending Email

Different user may want different email formatIT Dept. may decide to change how data is

storedBank might want to start using third party

email sending utility.

Single Responsibility PrincipleRefactorpublic class TransactionRepository

{…. }public class HTMLMailFormater

{….}public class EmailService {…….. }

Demo

Dependency InversionDepend upon abstractionHigh level module should not

depend upon low level module implementation, rather depend upon abstraction

Template pattern

Dependency InversionNaïve Example Demo

Dependency InversionProblem:-All the client must use text file to

store transactionSends email in HTML format onlyCode in BankAccount class, doesn’t

depend upon storage but still can’t be tested in isolation.

Why Keep Code Closed To ModificationsChanging Existing Code is Risky.Can be Time Consuming in a Non-Refactored

code base.

Code Not Designed on OCPprivate string SetDefaultEditableText(){

StringBuilder editableText = new StringBuilder();

switch ( SurveyManager.CurrentSurvey.TypeID ){

case 1:editableText.Append("<p>Text for Survey Type 2 Goes Here</p>");

case 2:editableText.Append("<p>Text for Survey Type 2 Goes Here</p>");case 3:default:editableText.Append("<p>Text for Survey Type 3 Goes Here</p>");

}return editableText.ToString();

}

Desigined For ExtensibilityStrategy Pattern (Composition focused)

interface ISurveyEmailFormatter{string GetDefaultEditableText();

}

public SurveyType1EmailFormatter : ISurveyEmailFormatter{public string GetDefaultEditableText(){

return "<p>Text for Survey Type 1 Goes Here</p>";}

}

public SurveyType2EmailFormatter : ISurveyEmailFormatter{public string GetDefaultEditableText(){

return "<p>Text for Survey Type 2 Goes Here</p>";}

}

public SurveyType3EmailFormatter : ISurveyEmailFormatter{public string GetDefaultEditableText(){

return "<p>Text for Survey Type 3 Goes Here</p>";}

}

Strategy Pattern Cont’dpublic class Survey{

IEmailFormatter _emailFormatter;public Survey(IEmailFormmater emailFormater){

_emailFormatter = emailFormatter;}

public string GetEmailDefaultText(){return _emailFormatter.GetDefaultEditableText();

}

}

Designed for ExtensibilityTemplate Pattern (Inheritance)public abstract Survey{

protected abstract string GetDefaultEditableText();public string GetEmailText(){ …

string defaultText = GetDefaultEditableText();…return somthingHere;

}

}

public SurveyType1{protected string GetDefaultEditableText(){

return "<p>Text for Survey Type 1 Goes Here</p>";}

}

Extensibility Only Goes So farChange is going to occur and you can’t keep

everything from changingMust use judgment on which parts of your

application are more likely to change and focus extensibility there.

Law of DemeterDon’t Talk To StrangersMethods Should Only Talk To:

Methods and fields on the ObjectParameters passed into the methodObjects Created within the method

Only one “dot”foo.bar.baz (bad)

DemeterBreaking this principle breaks encapsulation,

and tightens coupling.Refactoring much more difficult Test Setup becomes much more difficult

Interface Segregation PrincpleClients shouldn't be forced to

implement interfaces they don't use

Interface Segregation PrincpleExample of FAT or Polluted

Interface Try implementing custom Membership Provider in ASP.NET 2.0.

You just need to implement 27 methods/properties

Interface Segregation PrincpleInterface Idoor{

void Lock();void UnLock();bool IsOpen();

}Public Class Door : Idoor{

public void Lock() {}public void UnLock(){}bool IsOpen(){}

} <Demo>

Interface Segregation PrincpleConsider one implementation as security door which need

to ring alarm if door is kept open for longer duration.Interface Idoor{

void Lock();void UnLock();bool IsOpen();void Timeout();

}public class SecurityDoor : Idoor{

void Lock() {}void UnLock() {}bool IsOpen() {}void Timeout() {}

}<Demo>

Interface Segregation PrincpleProblemAll type of door are not timed By adding Timeout into IDoor we are

polluting our interface

Interface Segregation Princplepublic interface ITimerClient { void TimeOut(); }public class SecurityDoor : IDoor, ITimerClient {

public void TimeOut(){…….}

}

Demeterclass Wallet

attr_accessor :cash end class Customer

has_one :wallet end class Paperboy

def collect_money(customer, due_amount) if customer.wallet.cash < due_ammount raise InsufficientFundsError else customer.wallet.cash -= due_amount @collected_amount += due_amount end

end end

DemeterThe fix:class Wallet

attr_accessor :cash def withdraw(amount) raise InsufficientFundsError

if amount > cash cash -= amountamount

end end class Customer

has_one :wallet # behavior delegation def pay(amount)

@wallet.withdraw(amount) end

end class Paperboy

def collect_money(customer, due_amount) @collected_amount += customer.pay(due_amount)

end end

Liskov Substitution PrincipleAll sub-classes must be substitutable for their

base class.

Liskov violationStructural

You should not have to explicitly cast a base object to it’s subclass to do something.

BehaviorSubtypes should behave in a consistent manner

in terms of their clients

Liskov Examplepublic class Customer{

FirstName{get;set}LastName{get;set}Order GetOrder()

}

public class PreferredCustomer : Customer{double GetDiscount()

}

//voilationforeach(Customer c in CustomerList){

if(c is PreferredCustomer){GetDiscount();

}}

LiskovSubtypes should restrict the subclass, not

expand it.Use Composition to solve expansion

violations

Bottom line …SRP

Only one reason to changeDIP

“Don’t call me, I’ll call you”OCP

Open for extension, Closed for modificationLSP

Sub types should be substitutable for their bases types

LoD “Don’t talk to strangers”

ISP Clients should not be forced to depend on methods

they do not use

Remember… Always code as if the guy

maintaining your code would be a violent psychopath and

he knows where you live.

Recommended