Smell Detail

Middle Man

中间人

Couplers

Most of a class's methods simply delegate to other classes.

Define

Introduction

When most of a class's methods merely delegate to other classes, it becomes a Middle Man. The class may not need to exist; clients could work directly with the underlying collaborator.

Key Identifiers

  • Majority of methods are trivial delegations
  • The class adds no extra value or logic
  • Methods just forward calls verbatim
  • Adds an unnecessary layer of indirection

Refactoring Suggestions

  1. Remove Middle Man: Let clients talk directly to the delegated class
  2. Inline Method: Inline trivial delegation methods
  3. Selective Delegation: Keep only delegations that add value or simplify usage
  4. Replace Delegation with Inheritance: If appropriate and safe (rarely the first choice)

Explanation

The DatabaseManager class simply delegates to DatabaseConnection. Either use DatabaseConnection directly, or enrich DatabaseManager with meaningful behavior to justify its existence.

Code Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
class DatabaseConnection {
public void connect() {
System.out.println("Connecting to database...");
}
public void disconnect() {
System.out.println("Disconnecting from database...");
}
public void executeQuery(String sql) {
System.out.println("Executing: " + sql);
}
public void beginTransaction() {
System.out.println("Beginning transaction...");
}
public void commitTransaction() {
System.out.println("Committing transaction...");
}
public void rollbackTransaction() {
System.out.println("Rolling back transaction...");
}
public boolean isConnected() {
return true;
}
public void setConnectionTimeout(int timeout) {
System.out.println("Setting timeout to: " + timeout);
}
public String getConnectionString() {
return "jdbc:mysql://localhost:3306/mydb";
}
}
// This class simply delegates to DatabaseConnection
class DatabaseManager {
private DatabaseConnection connection;
public DatabaseManager() {
this.connection = new DatabaseConnection();
}
// All methods are simple delegations
public void connect() {
connection.connect();
}
public void disconnect() {
connection.disconnect();
}
public void executeQuery(String sql) {
connection.executeQuery(sql);
}
public void beginTransaction() {
connection.beginTransaction();
}
public void commitTransaction() {
connection.commitTransaction();
}
public void rollbackTransaction() {
connection.rollbackTransaction();
}
public boolean isConnected() {
return connection.isConnected();
}
public void setConnectionTimeout(int timeout) {
connection.setConnectionTimeout(timeout);
}
public String getConnectionString() {
return connection.getConnectionString();
}
}
// Another middle man example
class FileSystem {
public String readFile(String path) {
return "file content from " + path;
}
public void writeFile(String path, String content) {
System.out.println("Writing to " + path + ": " + content);
}
public boolean fileExists(String path) {
return true;
}
public long getFileSize(String path) {
return 1024;
}
public void deleteFile(String path) {
System.out.println("Deleting file: " + path);
}
}
class FileManager {
private FileSystem fs;
public FileManager() {
this.fs = new FileSystem();
}
// Simple delegations that add no value
public String read(String path) {
return fs.readFile(path);
}
public void write(String path, String content) {
fs.writeFile(path, content);
}
public boolean exists(String path) {
return fs.fileExists(path);
}
public long size(String path) {
return fs.getFileSize(path);
}
public void delete(String path) {
fs.deleteFile(path);
}
}
// Yet another example of unnecessary middle man
class Logger {
public void info(String message) {
System.out.println("[INFO] " + message);
}
public void error(String message) {
System.err.println("[ERROR] " + message);
}
public void debug(String message) {
System.out.println("[DEBUG] " + message);
}
public void warn(String message) {
System.out.println("[WARN] " + message);
}
}
class LoggingService {
private Logger logger;
public LoggingService() {
this.logger = new Logger();
}
// Pure delegation without adding value
public void logInfo(String message) {
logger.info(message);
}
public void logError(String message) {
logger.error(message);
}
public void logDebug(String message) {
logger.debug(message);
}
public void logWarning(String message) {
logger.warn(message);
}
}
// Example showing how middle man can be overused
class Calculator {
public int add(int a, int b) { return a + b; }
public int subtract(int a, int b) { return a - b; }
public int multiply(int a, int b) { return a * b; }
public double divide(int a, int b) { return (double) a / b; }
}
class MathService {
private Calculator calc;
public MathService() {
this.calc = new Calculator();
}
// Unnecessary delegation for simple operations
public int performAddition(int x, int y) {
return calc.add(x, y);
}
public int performSubtraction(int x, int y) {
return calc.subtract(x, y);
}
public int performMultiplication(int x, int y) {
return calc.multiply(x, y);
}
public double performDivision(int x, int y) {
return calc.divide(x, y);
}
}