module 3. smells between classes course: refactoring
TRANSCRIPT
Module 3. Smells Between Classes
Course: Refactoring
Overview: Smells Between Classes
Data
Inheritance
Responsibility
Accommodating Change
Library Classes
Lesson: Data
Primitive Obsession
Data Class
Data Clump
Temporary Field
Primitive Obsession
Symptoms Uses of the primitive or near-primitive types (int, float, String, etc.) Constants and enumerations representing small integers String constants representing field names
Causes Missing class Simulated types Simulated field accessors
What to Do Replace Data Value with Object
Replace Type Code with Class; Replace Type Code with Subclass; Replace Type Code with State/Strategy; Replace Conditional with Polymorphism
Replace Array with Object
Payoff Improves communication.
Data Class
Symptoms
class consists only of public data members
depend on the mutability and representation of the class
Causes
realize that some data is part of an independent object
What to Do
Encapsulate Field
Remove Setting Methods
Encapsulate Collection
Look at each client of the object.
Payoff
Improves communication.
Data Clump
Symptoms the same items frequently appear together in classes and parameter
lists. there are groups of fields and methods together within the class groups of field names start or end with similar substrings.
Causes The items are typically part of some other entity
What to Do Extract Class. Introduce Parameter Object Preserve Whole Object Move Method, etc
Payoff Improves communication. May expose duplication. Usually reduces
size.
Temporary Field
Symptoms
A field is set only at certain times, and it is null (or unused) at other times.
Causes
an algorithm that passes around information through the fields
What to Do
Extract Class
Payoff
Improves communication and clarity.
Exercise:
• Alternative Representations• Proper Names (Challenging)
Lesson: Inheritance
Refused Bequest
Inappropriate Intimacy (Subclass Form)
Lazy Class
See also these other smells related to inheritance:
Simulated Inheritance (Switch Statement) Parallel Inheritance Hierarchies Combinatorial Explosion
Refused Bequest
Symptoms honest refusal implicit refusal through a handle to the subclasses. Inheritance doesn't really make sense
Causes a class may inherit without really intending the class to be
substitutable a conscious decision to let subclasses deny use of some
features
What to Do you might decide to leave it as is. Replace Inheritance with Delegation. Extract Subclass, Push Down Field, and Push Down Method
Inappropriate Intimacy (Subclass Form)
Symptoms
A class accesses internal (should-be-private) parts of its parent.
Causes
Parent and child classes be more coupled together
What to Do
Self Encapsulate Field.
Form Template Method.
Replace Inheritance with Delegation.
Payoff
Reduces duplication.
Often improves communication.
May reduce size.
Lazy Class
Symptoms
A class isn't doing.
Causes
all responsibilities have been moved to other places
What to Do
Collapse Hierarchy.
Inline Class.
Payoff
Reduces size. Improves communication. Improves simplicity.
Exercise:
Collection classes
Real application
Lesson: Responsibility
Feature Envy
Inappropriate Intimacy (General Form)
Message Chains
Middle Man
Feature Envy
Symptoms
A method seems to be focused on manipulating the data of other classes rather than its own.
Causes
This is very common among clients of current and former data classes, but you can see it for any class and its clients.
What to Do
Move Method
Extract Method
Inappropriate Intimacy (General Form)
Symptoms One class accesses internal (should-be-private) parts of another
class
Causes The two classes probably became intertwined a little at a time. There may be a missing class that should mediate between them.
What to Do Move Method and Move Field Extract Class and Hide Delegate Change Bidirectional Reference to Unidirectional If a subclass is too coupled to its parent
Self Encapsulate Field.
Form Template Method.
Replace Inheritance with Delegation.
Message Chains
Symptoms
You see calls of the form:a.b().c().d()
Causes
the problem is that this couples both the objects and the path to get to them.
What to Do
Extract Method and Move Method
Use Hide Delegate
Middle Man
Symptoms object:f()
{ delegate.f(); }
Causes result from applying Hide Delegate to address
Message Chains
What to Do Remove Middle Man Replace Delegation with Inheritance.
Payoff Reduces size.
Exercise:
Middle Man
Account Cart
Exercise: Hide delegate
Lesson: Accommodating Change
Divergent Change
Shotgun Surgery
Parallel Inheritance Hierarchies
Combinatorial Explosion
Divergent Change
Symptoms
You find yourself changing the same class for different reasons.
Causes
The class picks up more responsibilities as it evolves
What to Do
Extract Class
Extract Superclass or Extract Subclass
Shotgun Surgery
Symptoms
Simple change requires to change several classes.
Causes
One responsibility is split among several classes.
Elimination Divergent Change.
What to Do
Extract Class
Move Field and Move Method.
Parallel Inheritance Hierarchies
Symptoms
required subclass in another hierarchy.
subclasses have the same prefix
a special case of Shotgun Surgery
Causes
The hierarchies probably grew in parallel, a class and its pair being needed at the same time.
What to Do
Move Field and Move Method
Payoff
Reduces duplication. May improve communication. May reduce size.
Combinatorial Explosion
Symptoms
you have to introduce multiple classes at various points of the hierarchy.
you notice that each layer of the hierarchy uses a common set of words
Causes
independent decisions instead get implemented via a hierarchy.
What to Do
Replace Inheritance with Delegation
Tease Apart Inheritance
Exercise:
Divergent Changes (csv writer)
Shotgun Surgery
Documents
Exercise: Shotgun Surgery
In code you have access to, find examples of this problem. Some frequent candidates:
Configuration information. Logging. Persistence. Sometimes it takes two calls on an object
to get something common done, and this two-step process is used in several places.
Lesson: Library Classes
Incomplete Library Class
Incomplete Library Class
Symptoms
library has no some features
Causes
the author of the library class didn't anticipate your need
What to Do
contact owner
Introduce Foreign Method
Introduce Local Extension
introduce a layer covering the library
Exercise:
Exercise:
Redraw this as a UML package diagram showing dependencies.
Explain how the bulk of your code does or does not depend on the library code in each of these situations.
What effects does this layering have in terms of:
Conceptual integrity?
Portability?
Performance?
Testing?
Exercise:
Review
Data
Inheritance
Responsibility
Accommodating Change
Library Classes
Gen-A-Refactoring
(—) in combinations that don't make sense,
(+) in those that are in Fowler's Refactoring catalog
(*) in those that make sense but aren't in the catalog.