Category
Couplers
Smells where classes depend too much on each other's data or structure, or where delegation is overused, so one change ripples through others.
What these smells share
Couplers are about the lines between classes, not the classes themselves. Either behavior sits in the wrong class and keeps reaching for another's data, or callers know too much about how objects are wired together, or a class adds a layer that only forwards.
Too much coupling makes changes spread. Too much indirection makes code hard to follow. These smells pull in both directions, so fixing one can create another.
Members
- Feature Envy: a method uses another object's data more than its own.
- Inappropriate Intimacy: two classes reach into each other's private parts.
- Message Chains: clients navigate
a.b().c().d()to reach what they need. - Middle Man: a class mostly forwards calls to another and adds nothing.
How to choose within this category
- One method leaning on one other class is Feature Envy. Move the method.
- Two classes leaning on each other, in both directions, is Inappropriate Intimacy. Separate the owners.
- A client walking through several objects is Message Chains. Hide the path behind the first object.
- A class that is all forwarding is Middle Man. Remove the layer.
- Message Chains and Middle Man are opposites. Hide Delegate fixes chains but, overused, creates a middle man; Remove Middle Man fixes the middle man but can bring chains back. Aim for the balance where clients depend on a near neighbor and each forwarding method has callers.
Typical treatments
- Move Method and Move Field for envy and intimacy.
- Extract Class and Change Bidirectional Association to Unidirectional to untangle two-way dependencies.
- Hide Delegate for chains.
- Remove Middle Man and Inline Method for pure forwarders.
For agents
- Some forwarding is intentional. Facade, Proxy, Adapter and Decorator are wrappers by design. Do not remove them as middle men.
- Some separation of data and behavior is intentional. Strategy and Visitor put logic outside the data on purpose.
- Check for import cycles before and after moving members between modules.
See also
- Change PreventersSmells where one change forces edits in many places, or one class changes for many unrelated reasons, making every edit slow and risky.
- DispensablesSmells where code, comments or abstractions add nothing, and removing them makes the program shorter and clearer with no loss of behavior.
- Move MethodMove a method to the class whose data it uses most, and leave a delegating call or update the callers.
- Hide DelegateAdd a method on the server object that forwards to its delegate, so clients stop navigating through it to reach the delegate.
- Remove Middle ManLet clients call the delegate directly when a class does little more than forward calls to it.
Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.