ood smells and principles ood smells and principles
play

OOD Smells and Principles OOD Smells and Principles S ingle - PowerPoint PPT Presentation

Contents Unplesant Code Smells vs. Refactoring Unplesant Code Smells vs. Refactoring Bad Design Smells vs. Design Principles SOLID OOD Smells and Principles OOD Smells and Principles S ingle Responsibility Principle (SRP) O


  1. Contents  Unplesant Code Smells vs. Refactoring  Unplesant Code Smells vs. Refactoring  Bad Design Smells vs. Design Principles – SOLID OOD Smells and Principles OOD Smells and Principles  S ingle Responsibility Principle (SRP)  O pen Closed Principle (OCP)  O pen Closed Principle (OCP)  L iskov Substitution Principle (LSP) C C++ Object Oriented Programming Obj O i d P i  I nterface Segregation Principle (ISP) I Pei-yih Ting  D ependency Inversion Principle (DIP) p y p ( ) NTOUCS  Other Design Principles 31-1 31-2 Unpleasant Code Smells p Refactoring  Refactoring : A change made to the internal structure of software to Refactoring: Improving the Design of Existing Code by M. Fowler et. al. make it easier to understand and cheaper to modify without p y 1 D 1. Duplicated Code li t d C d 12 L 12. Lazy Class Cl changing its observable behavior . 2. Long Method 13. Speculative Generality  Refactor : Restructure software by applying a series of refactorings 3. Large Class 3 Large Class 14 Temporary Field 14. Temporary Field without changing its observable behavior . ith t h i it b bl b h i 4. Long Parameter List 15. Message Chains  Kent Beck's two hats metaphor in developing software: 5. Divergent Change g g 16. Middle Man  You try to add a new functionality , and realize that it would be Y dd f ti lit d li h i ld b 6. Shotgun Surgery 17. Inappropriate Intimacy much easier if the code were structured differently. 7. Feature Envy 18. Alternative Classes with  So you swap hats and refactor for a while.  So you swap hats and refactor for a while. Different Interfaces 8. Data Clumps  Refactorings : https://sourcemaking.com/refactoring 19. Incomplete Library Class 9. Primitive Obsession  Composing methods (Extract method, Inline method, Inline temp, …) 20. Data Class 20 D t Cl 10. Switch Statements  Moving features between objects (Move method, …) 21. Refused Bequest 11. Parallel Inheritance  Organizing data (Self encapsulate field, …) Hierarchies Hierarchies 22 Comments 22. Comments  Simplifying conditional expression (…)  Simplifying conditional expression ( )  Making method call simpler (…) https://refactoring.com/catalog/ https://sourcemaking.com/refactoring/bad-smells-in-code  Dealing with generalization (…) 31-3 31-4

  2. Bad Design Smells g Agile Design g g  Rigidity – The system is hard to change because every change Software design involves iterations of the following steps: forces many other changes to other unrelated parts of the system forces many other changes to other unrelated parts of the system  Step 1 : Design and implement the required functions S 1 D i d i l h i d f i  Fragility – Changes cause the system to break in places that have no  Step 2 : Diagnose the problem following the smell of poor design conceptual relationship to the part that was changed conceptual relationship to the part that was changed and applying design principles and appl ing design principles  Immobility – It is hard to disentangle the system into components  Step 3 : Solve the problem by applying appropriate design pattern that can be reused in other systems. y  Viscosity – Doing things right is harder than doing things wrong.  Agile teams apply principles to remove bad smells.  Needless Complexity – The design contains infrastructure that adds p y g They don’t apply principles when there are no smells. Th d ’ l i i l h h ll no direct benefit.  Needless Repetition – The design contains repeating structures that could be unified under a single abstraction.  It is a mistake to unconditionally conform to a principle.  Opacity – The design is hard to read and hard to understand. It Indeed, over-conformance to a principle leads to the , p p does not express its intents well. design smell of Needless complexity. 31-5 31-6 S ingle R esponsibility P rinciple S g e espo s b y c p e Separated Responsibilities p p A class should have only one reason to change.  Separate two responsibilities into two completely different classes p p p y  Each responsibility is an axis of change When the requirements  Each responsibility is an axis of change. When the requirements by moving the computational portions of the Rectangle into the change, that change is likely manifest through a change in GeometricRectangle class. responsibility amongst the classes.  If a class has more than one responsibility, then the responsibilities become coupled. Changes to one responsibility may impair or inhibit the ability of the class to meet other requirements. the ability of the class to meet other requirements Computational Computational G Graphical hi l Geometry Application  Thus, it is important to separate different responsibilities into Application separate classes. p Rectangle Computational Graphical Graphical G Geometry +draw() Application Possible problems : Application GeometricRectangle Rectangle +area(): double GUI  Computational Geometry +area(): double +draw() GUI Application depends on GUI transitively.  area() and draw() are two unrelated responsibilities  Now changes made to the way rectangles are rendered cannot affect g y g If GraphicalApplication causes draw() to change or GUI changes If GraphicalApplication causes draw() to change or GUI changes the ComputationalGeometryApplication . somehow, these changes force us to rebuild, retest, and redeploy the ComputationalGeometryApplication. 31-7 31-8

  3. O pen C losed P rinciple O pen C losed P rinciple SRP Violation class Modem {  Two responsibilities: Software entities (classes, modules, functions, etc.) public:  connection management g should be open for extension, but closed for modification . h ld b f t i b t l d f difi ti void dial(string phoneNo); id di l( t i h N )  data communication void hangup();  Open for extension: the behavior of the module can be extended. As void send(char c); Should these two responsibilities Should these two responsibilities char recv(); char recv(); the requirements of the application change, we are able to extend the th i t f th li ti h bl t t d th be separated as two classes? }; module with new behaviors that satisfy those requirement changes.  Closed for modification : Extending the behavior of a module does  Closed for modification : Extending the behavior of a module does  M  Maybe not, it depends on how the application is changing. b t it d d h th li ti i h i not result in changes to the source or object code of the module, even  If connection management signature changes alone , then the clients that use send() and recv() have to be recompiled and redeployed. the binary executable version of the module remains untouched. y  If, on the other hand, the application << interface >> << interface >>  How is it possible that the behaviors of a module can be modified Data is not changing in ways that cause the Connection Channel without changing its source code? How can one change what a g g g two responsibilities to change at +dial(pno:string) dial(pno:string) +send(c:char) d( h ) different times. +hangup() module does, without changing the module? +recv():char  Using separate interfaces (as used the key is Abstraction the key is Abstraction by Interface Segregation Principle) by Interface Segregation Principle) Modem is another way to decouple the clients. Interface (Design by Contract, DbC) Implementation 31-9 31-10 w/o Suitable Abstraction With Good Abstraction  In C++, it is possible to create abstractions that are fixed and yet  In C++, it is possible to create abstractions that are fixed and yet  When a single change to a program results in a cascade of changes to represent an unbounded group of possible behaviors represent an unbounded group of possible behaviors . The p p g g p f p p f p dependent modules the design smells of Rigidity dependent modules, the design smells of Rigidity . abstractions are abstract base classes , and the unbounded group of  Violation of OCP: simple client-server Client Server possible behaviors is represented by all possible derived classes Client is not open and closed. Client is not open and closed. << interface >>  OCP conforming designs: Whenever the server code changes, the client code must change. Client Client Interface  Strategy pattern struct Modem { enum Type {hayes, courrier, ernie} type; Client and Client Interface }; void logOn(Modem &m, string& pno, string& user, string& pw) { are both open and closed. struct Hayes { Server Modem::Type type; yp yp ; Policy Policy if (m.type == Modem::hayes) ( yp y ) program to a fixed interface fi d i f // Hayes related stuff dialHayes((Hayes&)m, pno); +PolicyFunction() }; (design-by-contract). else if (m.type == Modem::courrier) -ServiceFunction() struct Courrier { dialCourrier((Courrier&)m, pno, user); (( ) p ) Modem::Type type; ode :: ype type; // Courrier related stuff else if (m.type == Modem::ernie)  Template Method pattern Implementation }; dialErnie((Ernie&)m, pno, user, pw); struct Ernie { -ServiceFunction() Policy is both open and closed. // … Adding a new modem would add Adding a new modem would add Modem::Type type; Modem::Type type; } // Ernie related stuff else if (m.type == Modem::xxx)  If OCP is applied well, further changes of that kind will be achieved }; … by adding new codes , not by changing old codes that already work. everywhere in its client programs 31-11 31-12

Recommend


More recommend