“odds & ends”€¦ · •however, remember implementation inheritance vs specification...

35
“Odds & Ends” OOD Lecture 10

Upload: others

Post on 21-May-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

“Odds & Ends”

OOD

Lecture 10

Page 2: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

UML generalization notation

is-a implements = provides

Class1

Class2

«interface»Interface1

Class3 Class3

Interface1

Page 3: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Visitor pattern

• Separate an algorithm from the object structure on which it operates – Ability to add new operations to existing object

structures without modifying those structures

– Open/Closed principle

– Double dispatch

Page 5: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Visitor pattern: Car

class Car implements CarElement {

CarElement[] elements;

public Car() {

this.elements = new CarElement[] {

new Wheel("front left"),

new Wheel("front right"),

new Wheel("back left") ,

new Wheel("back right"),

new Body(),

new Engine() }; }

//public void accept…

Page 6: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Visitor pattern: Visitors class CarElementPrintVisitor implements CarElementVisitor { public void visit(Wheel wheel) { System.out.println("Visiting " + wheel.getName() + " wheel"); } public void visit(Engine engine) { System.out.println("Visiting engine"); } public void visit(Body body) { System.out.println("Visiting body"); } public void visit(Car car) { System.out.println("Visiting car"); } } //--- class CarElementDoVisitor implements CarElementVisitor { public void visit(Wheel wheel) { System.out.println("Kicking my " + wheel.getName() + " wheel"); } public void visit(Engine engine) { System.out.println("Starting my engine"); } public void visit(Body body) { System.out.println("Moving my body"); } public void visit(Car car) { System.out.println("Starting my car"); } } //--- public class VisitorDemo { static public void main(String[] args) { Car car = new Car(); car.accept(new CarElementPrintVisitor()); car.accept(new CarElementDoVisitor()); } }

Page 7: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Orthogonal regions

Equivalent in terms of concurrent states

Page 8: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Deployment

• ”Mapping software components onto hardware components” – Is the system distributed over several computers? – What hardware or other special nodes are involved in the

system? – Very strongly related to software architecture – Where is persistent storage handled?

• If we want fault-tolerance, we need at least two computers • If we want scalability, we need to e.g., minimise

bottlenecks or be able to replicate without inconsistencies • We want to reason about non-functional requirements • We want system assumptions to be written down

Page 9: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Essentials of deployment modelling

• Artefacts and components – Physical items like executables, source files,

documentation, etc.

• Nodes – Computational resources like a server, a DB, special

hardware like GPS’s

• Connections (associations) between artefacts, components, and nodes – See the cooperation and the hardware at the same

time

Page 10: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood
Page 11: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood
Page 12: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood
Page 13: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring

“Refactoring is a disciplined technique for

restructuring an existing body of code,

altering its internal structure without changing

its external behavior. Its heart is a series of

small behavior preserving transformations.” Martin Fowler (1999) Refactoring: Improving the Design of

Existing Code. ISBN 978-02-014-85677.

Page 14: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring

• What: Change the internal structure of a program without changing behaviour

• Why: Initial structure/low-level design decisions aren’t good anymore – Refactored code cleaner, easier to understand and reuse

• Danger: Refactoring can break the code • Solution: Unit testing and regression testing When you sense code rot: 1. Run the tests 2. Apply the refactoring transformation that gets rid of the smell 3. Re-run the tests, make sure result is as before

Page 15: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring patterns

Move method

• Pattern

– A method is, or will be, using or used by more features of another class than the class in which it is defined

• Solution

– Create a new method with a similar body in the class it uses most. Either turn the old method into a simple delegation, or remove it altogether

• Careful about the latter: someone might be using it

Page 16: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring patterns

Replace Delegation with Inheritance

• Pattern

– You're using delegation and are often writing many simple delegations for the entire interface

• Solution

– Make the delegating class a subclass of the delegate.

• However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Page 17: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring patterns

Replace Inheritance with Delegation

• Pattern

– A subclass uses only part of the interface of a super-class or does not want to inherit data

• Solution

– Create a field for the superclass, adjust methods to delegate to the superclass, and remove the sub-classing

Page 18: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring patterns

Replace Conditional with Polymorphism

• Pattern

– You have a conditional that chooses different behavior depending on the type of an object

• Solution

– Move each leg of the conditional to an overriding method in a subclass, and make the original method abstract

Page 19: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring patterns http://www.refactoring.com/catalog/index.html

1. Add Parameter 2. Change Bidirectional Association to Unidirectional 3. Change Reference to Value 4. Change Unidirectional Association to Bidirectional 5. Change Value to Reference 6. Collapse Hierarchy 7. Consolidate Conditional Expression 8. Consolidate Duplicate Conditional Fragments 9. Convert Dynamic to Static Construction 10. Convert Static to Dynamic Construction 11. Decompose Conditional 12. Duplicate Observed Data 13. Eliminate Inter-Entity Bean Communication 14. Encapsulate Collection 15. Encapsulate Downcast 16. Encapsulate Field 17. Extract Class 18. Extract Interface 19. Extract Method 20. Extract Package 21. Extract Subclass 22. Extract Superclass 23. Form Template Method 24. Hide Delegate 25. Hide Method 26. Hide presentation tier-specific details from the business tier 27. Inline Class 28. Inline Method 29. Inline Temp

30. Introduce A Controller 31. Introduce Assertion 32. Introduce Business Delegate 33. Introduce Explaining Variable 34. Introduce Foreign Method 35. Introduce Local Extension 36. Introduce Null Object 37. Introduce Parameter Object 38. Introduce Synchronizer Token 39. Localize Disparate Logic 40. Merge Session Beans 41. Move Business Logic to Session 42. Move Class 43. Move Field 44. Move Method 45. Parameterize Method 46. Preserve Whole Object 47. Pull Up Constructor Body 48. Pull Up Field 49. Pull Up Method 50. Push Down Field 51. Push Down Method 52. Reduce Scope of Variable 53. Refactor Architecture 54. Remove Assignments to Parameters 55. Remove Control Flag 56. Remove Double Negative 57. Remove Middle Man 58. Remove Parameter 59. Remove Setting Method 60. Rename Method 61. Replace Array with Object 62. Replace Assignment with Initialization 63. Replace Conditional with Polymorphism

64. Replace Conditional with Visitor 65. Replace Constructor with Factory Method 66. Replace Data Value with Object 67. Replace Delegation with Inheritance 68. Replace Error Code with Exception 69. Replace Exception with Test 70. Replace Inheritance with Delegation 71. Replace Iteration with Recursion 72. Replace Magic Number with Symbolic Constant 73. Replace Method with Method Object 74. Replace Nested Conditional with Guard Clauses 75. Replace Parameter with Explicit Methods 76. Replace Parameter with Method 77. Replace Record with Data Class 78. Replace Recursion with Iteration 79. Replace Static Variable with Parameter 80. Replace Subclass with Fields 81. Replace Temp with Query 82. Replace Type Code with Class 83. Replace Type Code with State/ Strategy 84. Replace Type Code with Subclasses 85. Reverse Conditional 86. Self Encapsulate Field 87. Separate Data Access Code 88. Separate Query from Modifier 89. Split Loop 90. Split Temporary Variable 91. Substitute Algorithm 92. Use a Connection Pool 93. Wrap entities with session

Page 20: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Refactoring tools

• Many tools and IDE’s support refactoring operations – Better to use theirs than do it yourself!

– Global re-naming and other propagating changes resolved

• Finding opportunities for refactoring – Through code analysis, heuristics

– Faster, not always more accurate

– Mostly relies on some human supervision (at this point)

• Remember: Refactoring is language and tool agnostic (there is no excuse)

Page 21: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood
Page 22: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

API

• Application Programming Interface An interface to a piece of software that allows ”programming against it”

• In OOD, standard API constructs are – Classes — extended through sub-classing or

instantiated – Interfaces — implemented as services required or

provided – Components (but more COP, not OOP)

• Example: JDK, commonly referred to as the Java API’s

Page 23: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Why talk about API design?

• All programming is basically API design • If code is modular, it’s packages need good API’s to

work • Bad API = no or less reuse • Programming as developing of API’s promote good

design • Information hiding, exposing important parts in the

right ways • Low coupling, High cohesion • Getting API’s right from the start can be important • Public interfaces are hard to change • See e.g., JDK classes

Page 24: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Cohesion

• High functional cohesion is desirable – Conceptual integrity, no arbitrary dependencies

– Enhance robustness, reliability, reusability, and makes easier to understand

• Simple OO cohesion check for a class – Does its methods behave similarly? (The more they do, the

more cohesion)

– American-style inheritance can lead to low cohesion

• Break out different functionalities in separate classes

• Performance overhead of separation is generally negligible

Page 25: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Coupling and cohesion

• Coupling: The degree to which program modules rely on each other modules

• Cohesion: How strongly related the functionality expressed by the source code of a software module is

Page 26: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Characteristics of a Good API

• Easy to learn

• Easy to use, even without documentation

• Hard to misuse

• Easy to read and maintain code that uses it

• Sufficiently powerful to satisfy requirements

• Easy to extend

• Appropriate to audience

Page 27: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Coupling

• Low coupling is desirable – Easy to test or reuse without propagating inclusion – Less co-ordination between components is easier to

maintain and develop

• Sub-classing means one-directed coupling – Changes to superclass propagates to subclass – Subclass can have privileged access (to protected

members)

• Information hiding is key – Interaction via stable interface effectively decouples

components

Page 28: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

General Principles for API Design

• An API should do one thing, and do it well • Functionality should be easy to explain • ”When in doubt leave it out”

– You can add, but never remove

• Look for a good power-to-weight ratio • Expect to make mistakes

– A few years of real-world use will flush them out

• Start programming against the API before it is finished • Start programming against the API before it is properly

specified – Good ways of getting some unit test cases

Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters

Page 29: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Delay that order!

• Separate interface from implementation – Interface will be hard to modify later on, though you

will want to

– You will need to modify the implementation later on

• Implementation details are complex and confuse users, limit your freedom

• Over-specifying method behaviours limits your future freedom – e.g., don’t specify hashing functions

– be wary of tuning parameters

Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters

Page 30: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Effects of API Design Decisions on Performance

are Real and Permanent

• java.awt.Component.getSize() returns Dimension

• Dimension is mutable (bad thing!)

• Each getSize() call must allocate a Dimension instance

• Causes millions of needless object allocations

• Alternative added in Java 1.2

– But old client code still slow Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters

Page 31: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Maximise Information Hiding and Encapsulation

• Minimize Accessibility of Everything

– Make class members private (not even protected)

– No public fields in public classes

• We want components to be usable, understandable and testable in isolation

Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters

Page 32: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Class design

• Minimise mutability – Don’t make instances mutable unless there is a good

reason to – Necessary mutable state should be as little as possible – Method’s effects clear (e.g., Ruby’s ! naming convention)

• Advantages: simple, thread-safe and reusable • Disadvantages: one object for each value, no stable

identities Bad examples: Java’s Date & Calendar classes Good examples: TimerTask

Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters

Page 33: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Building an API is Like Building a Language

• Client code will hopefully be expressed mostly in terms of your language – ”Code that speaks the language of the domain” – ”Code should read like prose”

• Names Should Be Largely Self-Explanatory • Be consistent — same word means same thing

– Throughout API and across APIs on the platform

• Strive for symmetry and regularity • Follow the existing rules for the environment

– e.g., obey standard naming conventions

Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters

Page 34: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Class design

• Don’t subclass casually (and only use Scandinavian style) – Remember sub-classing increases coupling – Composition is often the proper way to go

• When you use inheritance, design for it and document – What are the assumptions method m makes on the other

methods? – All concrete classes final

Bad examples: Many concrete classes in J2SE libraries Good examples: AbstractSet, AbstractMap

Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters

Page 35: “Odds & Ends”€¦ · •However, remember implementation inheritance vs specification inheritance. If others are using your code, the former is often misused/misunderstood

Method design

• Don’t push things to the client that the API could solve internally

• Boilerplate code is evil and error-prone • Follow principle of least surprise, even when it costs

performance • Use static typing and generics to capture errors at compile-

time • Fail fast, ”crash don’t thrash” • Provide programmatic access to data elements rather than

just string form – Or that string format will become the de-facto API

• Favour interface types rather than class types for parameters and returns

• Use most specific possible input parameter type Adapted from Joshua Bloch’s How to Design a Good API and Why it Matters