high cohesion low coupling old standards for object oriented programming
TRANSCRIPT
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.