Smart People · Smart Solutions
Object Oriented Design Principles Session 1 – Getting a S.O.L.I.D understanding of the basic principles
Why do we need to know this? Dependency Management is an issue that most of us have faced. Poor dependency management leads to code that is hard to change, fragile, and non-reusable. When dependencies are well managed, the code remains flexible, robust, and reusable. - Robert C Martin (father of OOD)
What would we like to achieve here… Write more maintainable code Write more reusable code Write more testable code Write packages that are easier to deploy
The Basic Concepts of OO - Encapsulation Encapsulation is the hiding of non-essential features
The Basic Concepts of OO - Abstraction The mechanism and practice of abstraction is to reduce and factor out details so that one can focus on a few concepts at a time i.e. make things simpler Abstraction is the representation of only the essential features of an object
The Basic Concepts of OO - Inheritance A way to form new classes (instances of which are called objects) using classes that have already been defined. Inheritance is intended to help reuse existing code with little or no modification.
The Basic Concepts of OO - Polymorphism Polymorphism refers to the ability to define multiple classes with functionally different, yet identically named methods or properties that can be used interchangeably by client code at run time See code Example
The Basic Concepts of OO - Polymorphism public void ShowPolyMorphismExample() { DerivedClass B = new DerivedClass(); DoWork( B ); BaseClass A = (BaseClass) B ; DoWork( A ); DerivedClass2 C = new DerivedClass2(); DoWork( C ); } public void DoWork (BaseClass baseClass) { baseClass.DoWork(); } public class DerivedClass2 : BaseClass { public override void DoWork() { } public override int WorkProperty { get { return 0; } } } public class DerivedClass : BaseClass { public override void DoWork() { } public override int WorkProperty { get { return 0; } } } public class BaseClass { public virtual void DoWork() { } public virtual int WorkProperty { get { return 0; } } }
The Basic Concepts of OO – Decoupling Decoupling allows for the separation of object interactions from classes and inheritance into distinct layers of abstraction, for ex. Decoupling business logic from presentation (front end) logic A common use of decoupling is to polymorphically decouple the encapsulation, which is the practice of using reusable code to prevent discrete code modules from interacting with each other. In practice, decoupling often involves trade-offs with regard to which patterns of change to favor.
The Basic Concepts of OO - Getting a S.O.L.I.D understanding of the basic principles
What is S.O.L.I.D.? S.O.L.I.D. is a collection of best-practice, object-oriented design principles which can be applied to your design, allowing you to accomplish various desirable goals such as loose-coupling, higher maintainability, intuitive location of interesting code, etc.
What is S.O.L.I.D.? Each of the various letters in the S.O.L.I.D. acronym is yet another acronym SRP: Single Responsibility Principle THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE. OCP: Open Closed Principle SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION . LSP: Liskov Substitution Principle FUNCTIONS THAT USE ... REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT. ISP: Interface Segregation Principle CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE DIP: Dependency Inversion Principle A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS
SRP: Single Responsibility Principle THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.
SRP: Single Responsibility Principle Method/object should only have one reason to change Some of the factors that should be taken into account when applying SRP: Is this code reusable? How often will it change? What is required of the code now vs how you want to refactor it Which costs will be involved should you refactor this Money Time Applications affected Etc…
SRP: Single Responsibility Principle Whats wrong/right with these pics?
SRP – Problem vs Solution [code example] How can we improve this code: Lets create a type against which we can store the product info Lets extract the loading of products to a separate component How are things looking now? Can we still refactor?
SRP – Problem vs Solution [code example] How can we improve this code: Lets separate the logic not related to the form (using the MVP pattern in this case) This pattern must separate the concerns of a) visualization, b) orchestration (task delegation) and c) (data-) model
SRP – Problem vs Solution [code example] A quick rundown of the MVP Model-view-presenter (MVP) is a user interface design pattern engineered to facilitate automated unit testing and improve the separation of concerns in presentation logic – Wikipedia Advantages: Allows us to write test scripts to test the UI, for ex. By decoupling code in the presenter level, we can now reuse this code in different presentation technologies, like Winforms or Webforms You can code the logic before you have the UI coded
SRP – Problem vs Solution [code example] Let's analyze what the responsibility of the view should be delegate the user's request to choose an XML document to the presenter delegate the user's request to load the data from the selected XML document to the presenter provide the name of the selected XML document to the presenter accept a file name (of a selected XML document) from the presenter display a given list of products provided by the presenter (in a ListView control)
SRP – Problem vs Solution [code example] How can we improve this code: There are still 3 concerns handled by the repository class Retrieval of data Looping over nodes in the XML document Mapping the xml node to a product
SRP – Problem vs Solution [code example] Lets extract separate components what will load the data and map the data
SRP – Problem vs Solution [code example] Lets extract separate components what will load the data and map the data
SRP – Problem vs Solution [code example] All done! Each component now has a single responsibility
OCP: Open Closed Principle SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION .
OCP: Open Closed Principle Open for extension the behavior can be extended Closed for modification No one should ever need change that class’s code This means that: New requirement = new code, not changing existing, working code Depending on where OCP is implemented, some classes will never be 100% closed.. Thus strategic closure is required Make sure the OCP is implemented for most probable changes
OCP: Open Closed Principle Bertrand Meyer’s Version Robert C Martin Logger BaseLogger Logger DBLogger Logger DBLogger Logger DBLogger DBLogger Logger DBLogger DBLogger Logger DBLogger BaseLogger DBLogger Logger DBLogger Logger BaseLogger DBLogger Logger DBLogger
OCP: Where and when View Business Database System 1
OCP: Where and when View Business Database System 1
OCP: Where and when View Business Database System 1 View Database System 2
OCP: Where and when View Business Database System 1 View Database System 2
OCP: Possible Approach: Public vs Private Make all public member/global variables private This will reduce the impact that changing that variable has In OOD, we expect that methods of the class are not closed to its member variable We do expect that any other class (incl subclasses) are closed against changes to those variables If the variable is public and never changes, rather wrap it inside a public read-only property Whichever route is taken, the designer must asses how much closure is sacrificed and what the cost is of the public/global convenience
OCP: Possible Approach: Inheritance using Interfaces Create interfaces representing the various contracts (howbeit a very shallow contract… ito the real definition of a contract) Pros Every new requirement will result in a new class adhering to that interface Changes to closed classes will only result in changes made to one specific class… should you need to change the class, at least its encapsulated Very flexible classes Cons Classes can be come very cluttered
OCP: Possible Approach: Polymorphism Create base classes that subclasses can extend Pros Code can be reused since the subclass may choose to override certain base methods (where virtual methods are used) Cons Should the base class need to change for some reason, the knock-on effect may be huge ie more difficult to reuse
OCP: Code Example – The Logger We have an AuthenticationService that uses a Logger to write debug, info and error messages. The client has requested that it should also be able to log to the database. How can we improve our current “bad” solution to conform to the OCP
OCP: Code Example – The Logger Inheritance using Interfaces We create a logger Interface that our two loggers (the original logger and new DBLogger will implement)
OCP: Code Example – The Logger Polymorphism We create an abstract class that the logger and db logger will inherit off from. Reusable functionality between the two loggers can be captured in the abstract class
OCP: Code Example – Practicalities So OCP is achieved for the following scenario: Changing the Authentication service to use a different logger when required…. 1) We don’t need to change AuthenticationService if we want to use a new logger 2) AuthenticationService can now use any logger Lets say we want to add another Logging method just to the logging class (not the DBLogger), called “Warning”. Does the current solution conform to the OCP for the new requirement? Why?
OCP: Code Example – Field Validation We have class that uses validation. Since we know that these validation methods can be reused, we decide to abstract them into a separate class… How would we apply OCP in order to make the validation class extendable, ito adding new rules, but closed to modification?
We have closed the validation class so that no changes should ever need to be made if you want to add new validation rules The class is extendable in the sense that it can validate any set of validation rules OCP: Code Example – Field Validation
LSP: Liskov Substitution Principle If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
LSP: Liskov Substitution Principle FUNCTIONS THAT USE ... REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT.
LSP: Violation 1 Whats wrong with this code? This function violates both LSP and OCP… This function is aware of all the various implementations of shape The extension of shape has not been closed properly
LSP: Violation 2 Consider the following class diagram…
LSP: Violation 2 Given the previous class diagram… what will happen here….
LSP: Liskov Substitution Principle A model viewed in isolation, can not be meaningfully validated When considering whether a particular design is correct or not, review the solution according to the assumptions that will be made by its users When using an object via its base class interface, you must accept anything the base class could accept Bertrand Meyer’s Design by Contract ...when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one
ISP: Interface Segregation Principle CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE
ISP: Interface Segregation Principle If you have an abstract class or interface, its implementers should not be forced to implement parts it doesn’t care about Any changes made to these fat interfaces or abstract classes are most likely force a change to its implementers.
ISP: Example 1 The carconfigurator class implements an interface that exposes 3 properties: EngineType, ExteriorColour and InteriorColour. 3 separate classes are used to draw each property (they each accept an implementation of carconfigurator)… Whats wrong with this….
ISP: Example 1 Now, the interfaces are less likely to become bloated. Changes to the interfaces are now only restricted to the classes that use those interfaces
ISP: Example 2 There are two animals (dog and rattlesnake) that inherit off an abstract animal class. Both classes override the feed and groom methods But would really groom a rattlesnake? In this case, you wont, so the method is ignored… Whats wrong with this?
ISP: Example 2 The animal class is no longer bloated. This gives us the option to customize our derived classes to be more specific to our needs Also, should any changes be made to IPet, it will only affect Dog
DIP: Dependency Inversion Principle HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS
DIP: Dependency Inversion Principle DIP is used to alleviate badly designed code, that is code that is: Rigid (single change will affect many other parts) Fragile (single change may cause unexpected parts to break) Immobile (hard to reuse code in another application since it can’t be decoupled) DIP is not Dependency Injection Dependency Injection is a form of DIP DIP can be seen as a combination of 3 SOLID principles SRP, OCP and LSP
DIP: Dependency Inversion Principle According to Grady Booch: “...all well structured object-oriented architectures have clearly-defined layers, with each layer providing some coherent set of services though a well-defined and controlled interface.” So whats wrong with this….
DIP: Dependency Inversion Principle According to DIP.. It should look something like this:
DIP: Example 1 We have an Order Processor that will calculate the total of an order. It takes the following into account: Item total Discount amount (if any) Tax amount In this case, tax strategies from either US or UK can be applied… depending in which country the order was placed. Whats wrong with this code?
DIP: Example 1 What’s wrong with the code: OrderProcessor has too many responsibilities (Violates SRP) It’s not closed to the various possibilities of tax strategies (Violates OCP) So… how do we fix this? Remove its external dependencies: DiscountCalculator and Tax Decisions
DIP: Example 1 Two patterns introduced in order to help solve our problem Adapter Pattern Strategy Pattern Adapter Pattern (according to Wikipedia) translates one interface for a class into a compatible interface. An adapter allows classes to work together that normally could not because of incompatible interfaces, by providing its interface to clients while using the original interface. Strategy Pattern (according to Wikipedia) is a particular software design pattern, whereby algorithms can be selected at runtime The strategy pattern is useful for situations where it is necessary to dynamically swap the algorithms used in an application
DIP: Example 1 – Adapter Pattern Since DiscountCalculator is a static class, we can’t change it from a static to non-static class, since it might be reused by other apps Applying that Adapter Pattern will allow us to write our own wrapper for the class. Should the mechanism for calculating discounts changes, the OrderProcessor doesn’t need to change
DIP: Example 1 – Strategy Pattern Since we have various tax strategies with the possibility of many more, this pattern makes perfect sense… We can now swap out the various strategies without having to change the OrderProcessor
DIP: Example 1 – Final Solution
DIP: Example 1 – Final Solution Instead of the OrderProcessor depending directly on details, it depends solely on the abstracted interfaces I can reuse the existing Discount Calculator with the added benefit that should it change, OrderProcessor wont need to change I can now swap out the various tax strategies without OrderProcessor having to change Since OrderProcessors dependencies have been factored out, its single responsibility can easily be discerned from looking at the code.
DIP: Other Example(s) Refer to the SRP code example (the Xml File Loading solution)
S.O.L.I.D – Conclusion (benefits) Low Coupling With OCP and DIP introduced, our system will have very low coupling… meaning we can modify behavior as needed, with little modification to the overall system High Cohesion Def : a measure of how strongly-related or focused the responsibilities of a single module are. In a highly-cohesive system, code readability and the likelihood of reuse is increased, while complexity is kept manageable With Low coupling and DIP, we can tie the small pieces of code together like building blocks
S.O.L.I.D – Conclusion (benefits) Encapsulation Not just making fields private but hiding implementation details from other objects LSP, DIP and SRP all work together to create true encapsulation We’ve prevented implementations of various objects to leak into each other while ensuring the dependencies by encapsulating them behind a known interface We’ve hidden implementation details and allowed for any implementation to be put in its place using DIP We’ve also ensured that we don’t violate any of the individual abstraction’s semantics (using LSP) so that we can safely replace the implementation as needed
S.O.L.I.D – Conclusion So did we meet our original requirements of what we wanted to archive through these sessions? Write more maintainable code Write more reusable code Write more testable code Write packages that are easier to deploy
S.O.L.I.D – Conclusion So did we meet our original requirements of what we wanted to archive through these sessions? Write more maintainable code Write more reusable code Write more testable code Write packages that are easier to deploy YES YES YES YES

Object Oriented Concepts and Principles

  • 1.
    Smart People · Smart Solutions
  • 2.
    Object Oriented Design Principles Session 1 – Getting a S.O.L.I.D understanding of the basic principles
  • 3.
    Why do weneed to know this? Dependency Management is an issue that most of us have faced. Poor dependency management leads to code that is hard to change, fragile, and non-reusable. When dependencies are well managed, the code remains flexible, robust, and reusable. - Robert C Martin (father of OOD)
  • 4.
    What would welike to achieve here… Write more maintainable code Write more reusable code Write more testable code Write packages that are easier to deploy
  • 5.
    The Basic Conceptsof OO - Encapsulation Encapsulation is the hiding of non-essential features
  • 6.
    The Basic Conceptsof OO - Abstraction The mechanism and practice of abstraction is to reduce and factor out details so that one can focus on a few concepts at a time i.e. make things simpler Abstraction is the representation of only the essential features of an object
  • 7.
    The Basic Conceptsof OO - Inheritance A way to form new classes (instances of which are called objects) using classes that have already been defined. Inheritance is intended to help reuse existing code with little or no modification.
  • 8.
    The Basic Conceptsof OO - Polymorphism Polymorphism refers to the ability to define multiple classes with functionally different, yet identically named methods or properties that can be used interchangeably by client code at run time See code Example
  • 9.
    The Basic Conceptsof OO - Polymorphism public void ShowPolyMorphismExample() { DerivedClass B = new DerivedClass(); DoWork( B ); BaseClass A = (BaseClass) B ; DoWork( A ); DerivedClass2 C = new DerivedClass2(); DoWork( C ); } public void DoWork (BaseClass baseClass) { baseClass.DoWork(); } public class DerivedClass2 : BaseClass { public override void DoWork() { } public override int WorkProperty { get { return 0; } } } public class DerivedClass : BaseClass { public override void DoWork() { } public override int WorkProperty { get { return 0; } } } public class BaseClass { public virtual void DoWork() { } public virtual int WorkProperty { get { return 0; } } }
  • 10.
    The Basic Conceptsof OO – Decoupling Decoupling allows for the separation of object interactions from classes and inheritance into distinct layers of abstraction, for ex. Decoupling business logic from presentation (front end) logic A common use of decoupling is to polymorphically decouple the encapsulation, which is the practice of using reusable code to prevent discrete code modules from interacting with each other. In practice, decoupling often involves trade-offs with regard to which patterns of change to favor.
  • 11.
    The Basic Conceptsof OO - Getting a S.O.L.I.D understanding of the basic principles
  • 12.
    What is S.O.L.I.D.?S.O.L.I.D. is a collection of best-practice, object-oriented design principles which can be applied to your design, allowing you to accomplish various desirable goals such as loose-coupling, higher maintainability, intuitive location of interesting code, etc.
  • 13.
    What is S.O.L.I.D.?Each of the various letters in the S.O.L.I.D. acronym is yet another acronym SRP: Single Responsibility Principle THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE. OCP: Open Closed Principle SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION . LSP: Liskov Substitution Principle FUNCTIONS THAT USE ... REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT. ISP: Interface Segregation Principle CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE DIP: Dependency Inversion Principle A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS
  • 14.
    SRP: Single ResponsibilityPrinciple THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.
  • 15.
    SRP: Single ResponsibilityPrinciple Method/object should only have one reason to change Some of the factors that should be taken into account when applying SRP: Is this code reusable? How often will it change? What is required of the code now vs how you want to refactor it Which costs will be involved should you refactor this Money Time Applications affected Etc…
  • 16.
    SRP: Single ResponsibilityPrinciple Whats wrong/right with these pics?
  • 17.
    SRP – Problemvs Solution [code example] How can we improve this code: Lets create a type against which we can store the product info Lets extract the loading of products to a separate component How are things looking now? Can we still refactor?
  • 18.
    SRP – Problemvs Solution [code example] How can we improve this code: Lets separate the logic not related to the form (using the MVP pattern in this case) This pattern must separate the concerns of a) visualization, b) orchestration (task delegation) and c) (data-) model
  • 19.
    SRP – Problemvs Solution [code example] A quick rundown of the MVP Model-view-presenter (MVP) is a user interface design pattern engineered to facilitate automated unit testing and improve the separation of concerns in presentation logic – Wikipedia Advantages: Allows us to write test scripts to test the UI, for ex. By decoupling code in the presenter level, we can now reuse this code in different presentation technologies, like Winforms or Webforms You can code the logic before you have the UI coded
  • 20.
    SRP – Problemvs Solution [code example] Let's analyze what the responsibility of the view should be delegate the user's request to choose an XML document to the presenter delegate the user's request to load the data from the selected XML document to the presenter provide the name of the selected XML document to the presenter accept a file name (of a selected XML document) from the presenter display a given list of products provided by the presenter (in a ListView control)
  • 21.
    SRP – Problemvs Solution [code example] How can we improve this code: There are still 3 concerns handled by the repository class Retrieval of data Looping over nodes in the XML document Mapping the xml node to a product
  • 22.
    SRP – Problemvs Solution [code example] Lets extract separate components what will load the data and map the data
  • 23.
    SRP – Problemvs Solution [code example] Lets extract separate components what will load the data and map the data
  • 24.
    SRP – Problemvs Solution [code example] All done! Each component now has a single responsibility
  • 25.
    OCP: Open ClosedPrinciple SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION .
  • 26.
    OCP: Open ClosedPrinciple Open for extension the behavior can be extended Closed for modification No one should ever need change that class’s code This means that: New requirement = new code, not changing existing, working code Depending on where OCP is implemented, some classes will never be 100% closed.. Thus strategic closure is required Make sure the OCP is implemented for most probable changes
  • 27.
    OCP: Open ClosedPrinciple Bertrand Meyer’s Version Robert C Martin Logger BaseLogger Logger DBLogger Logger DBLogger Logger DBLogger DBLogger Logger DBLogger DBLogger Logger DBLogger BaseLogger DBLogger Logger DBLogger Logger BaseLogger DBLogger Logger DBLogger
  • 28.
    OCP: Where andwhen View Business Database System 1
  • 29.
    OCP: Where andwhen View Business Database System 1
  • 30.
    OCP: Where andwhen View Business Database System 1 View Database System 2
  • 31.
    OCP: Where andwhen View Business Database System 1 View Database System 2
  • 32.
    OCP: Possible Approach:Public vs Private Make all public member/global variables private This will reduce the impact that changing that variable has In OOD, we expect that methods of the class are not closed to its member variable We do expect that any other class (incl subclasses) are closed against changes to those variables If the variable is public and never changes, rather wrap it inside a public read-only property Whichever route is taken, the designer must asses how much closure is sacrificed and what the cost is of the public/global convenience
  • 33.
    OCP: Possible Approach:Inheritance using Interfaces Create interfaces representing the various contracts (howbeit a very shallow contract… ito the real definition of a contract) Pros Every new requirement will result in a new class adhering to that interface Changes to closed classes will only result in changes made to one specific class… should you need to change the class, at least its encapsulated Very flexible classes Cons Classes can be come very cluttered
  • 34.
    OCP: Possible Approach:Polymorphism Create base classes that subclasses can extend Pros Code can be reused since the subclass may choose to override certain base methods (where virtual methods are used) Cons Should the base class need to change for some reason, the knock-on effect may be huge ie more difficult to reuse
  • 35.
    OCP: Code Example– The Logger We have an AuthenticationService that uses a Logger to write debug, info and error messages. The client has requested that it should also be able to log to the database. How can we improve our current “bad” solution to conform to the OCP
  • 36.
    OCP: Code Example– The Logger Inheritance using Interfaces We create a logger Interface that our two loggers (the original logger and new DBLogger will implement)
  • 37.
    OCP: Code Example– The Logger Polymorphism We create an abstract class that the logger and db logger will inherit off from. Reusable functionality between the two loggers can be captured in the abstract class
  • 38.
    OCP: Code Example– Practicalities So OCP is achieved for the following scenario: Changing the Authentication service to use a different logger when required…. 1) We don’t need to change AuthenticationService if we want to use a new logger 2) AuthenticationService can now use any logger Lets say we want to add another Logging method just to the logging class (not the DBLogger), called “Warning”. Does the current solution conform to the OCP for the new requirement? Why?
  • 39.
    OCP: Code Example– Field Validation We have class that uses validation. Since we know that these validation methods can be reused, we decide to abstract them into a separate class… How would we apply OCP in order to make the validation class extendable, ito adding new rules, but closed to modification?
  • 40.
    We have closedthe validation class so that no changes should ever need to be made if you want to add new validation rules The class is extendable in the sense that it can validate any set of validation rules OCP: Code Example – Field Validation
  • 41.
    LSP: Liskov SubstitutionPrinciple If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
  • 42.
    LSP: Liskov SubstitutionPrinciple FUNCTIONS THAT USE ... REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT.
  • 43.
    LSP: Violation 1Whats wrong with this code? This function violates both LSP and OCP… This function is aware of all the various implementations of shape The extension of shape has not been closed properly
  • 44.
    LSP: Violation 2Consider the following class diagram…
  • 45.
    LSP: Violation 2Given the previous class diagram… what will happen here….
  • 46.
    LSP: Liskov SubstitutionPrinciple A model viewed in isolation, can not be meaningfully validated When considering whether a particular design is correct or not, review the solution according to the assumptions that will be made by its users When using an object via its base class interface, you must accept anything the base class could accept Bertrand Meyer’s Design by Contract ...when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one
  • 47.
    ISP: Interface SegregationPrinciple CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE
  • 48.
    ISP: Interface SegregationPrinciple If you have an abstract class or interface, its implementers should not be forced to implement parts it doesn’t care about Any changes made to these fat interfaces or abstract classes are most likely force a change to its implementers.
  • 49.
    ISP: Example 1The carconfigurator class implements an interface that exposes 3 properties: EngineType, ExteriorColour and InteriorColour. 3 separate classes are used to draw each property (they each accept an implementation of carconfigurator)… Whats wrong with this….
  • 50.
    ISP: Example 1Now, the interfaces are less likely to become bloated. Changes to the interfaces are now only restricted to the classes that use those interfaces
  • 51.
    ISP: Example 2There are two animals (dog and rattlesnake) that inherit off an abstract animal class. Both classes override the feed and groom methods But would really groom a rattlesnake? In this case, you wont, so the method is ignored… Whats wrong with this?
  • 52.
    ISP: Example 2The animal class is no longer bloated. This gives us the option to customize our derived classes to be more specific to our needs Also, should any changes be made to IPet, it will only affect Dog
  • 53.
    DIP: Dependency InversionPrinciple HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS
  • 54.
    DIP: Dependency InversionPrinciple DIP is used to alleviate badly designed code, that is code that is: Rigid (single change will affect many other parts) Fragile (single change may cause unexpected parts to break) Immobile (hard to reuse code in another application since it can’t be decoupled) DIP is not Dependency Injection Dependency Injection is a form of DIP DIP can be seen as a combination of 3 SOLID principles SRP, OCP and LSP
  • 55.
    DIP: Dependency InversionPrinciple According to Grady Booch: “...all well structured object-oriented architectures have clearly-defined layers, with each layer providing some coherent set of services though a well-defined and controlled interface.” So whats wrong with this….
  • 56.
    DIP: Dependency InversionPrinciple According to DIP.. It should look something like this:
  • 57.
    DIP: Example 1 We have an Order Processor that will calculate the total of an order. It takes the following into account: Item total Discount amount (if any) Tax amount In this case, tax strategies from either US or UK can be applied… depending in which country the order was placed. Whats wrong with this code?
  • 58.
    DIP: Example 1What’s wrong with the code: OrderProcessor has too many responsibilities (Violates SRP) It’s not closed to the various possibilities of tax strategies (Violates OCP) So… how do we fix this? Remove its external dependencies: DiscountCalculator and Tax Decisions
  • 59.
    DIP: Example 1Two patterns introduced in order to help solve our problem Adapter Pattern Strategy Pattern Adapter Pattern (according to Wikipedia) translates one interface for a class into a compatible interface. An adapter allows classes to work together that normally could not because of incompatible interfaces, by providing its interface to clients while using the original interface. Strategy Pattern (according to Wikipedia) is a particular software design pattern, whereby algorithms can be selected at runtime The strategy pattern is useful for situations where it is necessary to dynamically swap the algorithms used in an application
  • 60.
    DIP: Example 1– Adapter Pattern Since DiscountCalculator is a static class, we can’t change it from a static to non-static class, since it might be reused by other apps Applying that Adapter Pattern will allow us to write our own wrapper for the class. Should the mechanism for calculating discounts changes, the OrderProcessor doesn’t need to change
  • 61.
    DIP: Example 1– Strategy Pattern Since we have various tax strategies with the possibility of many more, this pattern makes perfect sense… We can now swap out the various strategies without having to change the OrderProcessor
  • 62.
    DIP: Example 1– Final Solution
  • 63.
    DIP: Example 1– Final Solution Instead of the OrderProcessor depending directly on details, it depends solely on the abstracted interfaces I can reuse the existing Discount Calculator with the added benefit that should it change, OrderProcessor wont need to change I can now swap out the various tax strategies without OrderProcessor having to change Since OrderProcessors dependencies have been factored out, its single responsibility can easily be discerned from looking at the code.
  • 64.
    DIP: Other Example(s)Refer to the SRP code example (the Xml File Loading solution)
  • 65.
    S.O.L.I.D – Conclusion(benefits) Low Coupling With OCP and DIP introduced, our system will have very low coupling… meaning we can modify behavior as needed, with little modification to the overall system High Cohesion Def : a measure of how strongly-related or focused the responsibilities of a single module are. In a highly-cohesive system, code readability and the likelihood of reuse is increased, while complexity is kept manageable With Low coupling and DIP, we can tie the small pieces of code together like building blocks
  • 66.
    S.O.L.I.D – Conclusion(benefits) Encapsulation Not just making fields private but hiding implementation details from other objects LSP, DIP and SRP all work together to create true encapsulation We’ve prevented implementations of various objects to leak into each other while ensuring the dependencies by encapsulating them behind a known interface We’ve hidden implementation details and allowed for any implementation to be put in its place using DIP We’ve also ensured that we don’t violate any of the individual abstraction’s semantics (using LSP) so that we can safely replace the implementation as needed
  • 67.
    S.O.L.I.D – ConclusionSo did we meet our original requirements of what we wanted to archive through these sessions? Write more maintainable code Write more reusable code Write more testable code Write packages that are easier to deploy
  • 68.
    S.O.L.I.D – ConclusionSo did we meet our original requirements of what we wanted to archive through these sessions? Write more maintainable code Write more reusable code Write more testable code Write packages that are easier to deploy YES YES YES YES