Practical Object Oriented Design - KeynesYouDigIt/Knowledge GitHub Wiki
Designing Classes with a Single Responsibility
Deciding what belongs in a class
It's impossible to get it right up front.
Grouping Methods into Classes
Organizing Code to Allow for Easy Changes
"Easy to change" means:
- Changes have no unexpected side effects
- Small changes in requirements == small changes in code
- Existing code is easy to reuse
- The easiest way to make a change is to add code that in itself is easy to change
TRUE code:
- Transparent: Consequences of change should be obvious
- Reasonable: The cost of a change should be proportional to the benefits of the change
- Usable: Existing code should be usable in new and unexpected contexts
- Exemplary: The code itself should encourage those who change it to perpetuate these qualities
Creating Classes That Have a Single Responsibility
An Example Application: Bicycles and Gears
Why Single Responsibility Matters
Determining If a Class Has a Single Responsibility
Writing Code That Embraces Change
Depend on Behavior, Not Data
Enforce Single Responsibility Everywhere
Finally, the Real Wheel
Managing Dependencies
Understanding Dependencies
Recognizing Dependencies
Coupling Between Objects (CBO)
Other Dependencies
Writing Loosely Coupled Code
Inject Dependencies
Isolate Dependencies
Remove Argument-Order Dependencies
Managing Dependency Direction
Reversing Dependencies
Choosing Dependency Direction
Creating Flexible Interfaces
Understanding Interfaces
Defining Interfaces
Public interfaces
Private interfaces
Responsibilites, Dependencies, and Interfaces
Finding the Public Interface
An Example Application: Bicycle Touring Company
Constructing an Intention
Using Sequence Diagrams
Asking for "What" Instead of Telling "How"
Seeking Context Independence
Trusting Other Objects
Using Messages to Discover Objects
Creating a Message-Based Application
Writing Code That Puts Its Best (Inter)Face Forward
Create Explicit Interfaces
Honor the Public Interfaces of Others
Exercise Caution When Depending on Private Interfaces
Minimize Context
The Law of Demeter
Defining Demeter
Consequences of Violations
Avoiding Violations
Listening to Demeter
Reducing Costs with Duck Typing
Understanding Duck Typing
Overlooking the Duck
Compounding the Problem
Finding the Duck
Consequences of Duck Typing
Writing Code That Relies on Ducks
Recognizing Hidden Ducks
Placing Trust in Your Ducks
Documenting Duck Types
Sharing Code between Ducks
Choosing Your Ducks Wisely
Conquering a Fear of Duck Typing
Subverting Duck Types with Static Typing
Static vs. Dynamic Typing
Embracing Dynamic Typing
Acquiring Behavior through Inheritance
Understanding Classical Inheritance
Recognizing Where to Use Inheritance
Starting with a Concrete Class
Embedding Multiple Types
Finding the Embedded Types
Choosing Inheritance
Drawing Inheritance Relationships
Misapplying Inheritance
Finding the Abstraction
Creating an Abstract Superclass
Promoting Abstract Behavior
Separating Abstract from Concrete
Using the Template Method Pattern
Implementing Every Template Method
Managing Coupling between Superclasses and Subclasses
Understanding Coupling
Decoupling Subclasses Using Hook Messages
Sharing Role Behavior with Modules
Understanding Roles
Finding Roles
Organizing Responsibilities
Removing Unnecessary Dependencies
Writing the Concrete Code
Extracting the Abstraction
Looking Up Methods
Inheriting Role Behavior
Writing Inheritable Code
Recognize the Antipatterns
Insist on the Abstraction
Honor the Contract
Use the Template Method Pattern
Preemptively Decouple Classes
Create Shallow Hierarchies
Combining Objects with Composition
Composing a Bicycle of Parts
Updating the Bicycle Class
Creating a Parts Hierarchy
Composing the Parts Objects
Creating a Part
Making the Parts Object More Like an Array
Manufacturing Parts
Creating the PartsFactory
Leveraging the PartsFactory
The Composed Bicycle
Deciding Between Inheritance and Composition
Accepting the Consequences of Inheritance
Accepting the Consequences of Composition
Choosing Relationships
Designing Cost-Effective Tests
Intentional Testing
Knowing Your Intentions
Knowing What to Test
Knowing When to Test
- Incoming messages should be tested for the state they return
- Outgoing command messages should be tested to ensure they get sent
- Outgoing query messages should not be tested