Smell Detail

Repeated Switches

重复的 switch

Object-Orientation Abusers

Complex switch statements that could typically be replaced by polymorphism.

Define

Introduction

Complex switch statements often indicate missing polymorphism. Each time you add a new case, you must modify the switch, violating the Open/Closed Principle.

Key Identifiers

  • Large or complex switch / if-else chains
  • Same switch logic duplicated in multiple places
  • Adding a new type requires editing several switches
  • Violates the Open/Closed Principle

Refactoring Suggestions

  1. Replace with Polymorphism: Use inheritance and virtual/overridden methods instead
  2. Strategy Pattern: Encapsulate varying behavior in strategy classes
  3. State Pattern: For state-dependent switch logic

Explanation

Use polymorphism so each Shape class implements calculateArea() and draw(). Then adding a new shape doesn't require changes to existing code.

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
enum ShapeType {
RECTANGLE, CIRCLE, TRIANGLE, SQUARE
}
class Shape {
public ShapeType type;
public double width, height; // for rectangle
public double radius; // for circle
public double base; // for triangle
public double side; // for square
}
class ShapeProcessor {
public double calculateArea(Shape shape) {
switch (shape.type) {
case RECTANGLE:
return shape.width * shape.height;
case CIRCLE:
return Math.PI * shape.radius * shape.radius;
case TRIANGLE:
return 0.5 * shape.base * shape.height;
case SQUARE:
return shape.side * shape.side;
default:
return 0;
}
}
public void draw(Shape shape) {
switch (shape.type) {
case RECTANGLE:
drawRectangle(shape);
break;
case CIRCLE:
drawCircle(shape);
break;
case TRIANGLE:
drawTriangle(shape);
break;
case SQUARE:
drawSquare(shape);
break;
}
}
public double calculatePerimeter(Shape shape) {
switch (shape.type) {
case RECTANGLE:
return 2 * (shape.width + shape.height);
case CIRCLE:
return 2 * Math.PI * shape.radius;
case TRIANGLE:
// Simplified: assuming equilateral triangle
return 3 * shape.base;
case SQUARE:
return 4 * shape.side;
default:
return 0;
}
}
public String getDescription(Shape shape) {
switch (shape.type) {
case RECTANGLE:
return "Rectangle with width " + shape.width + " and height " + shape.height;
case CIRCLE:
return "Circle with radius " + shape.radius;
case TRIANGLE:
return "Triangle with base " + shape.base + " and height " + shape.height;
case SQUARE:
return "Square with side " + shape.side;
default:
return "Unknown shape";
}
}
private void drawRectangle(Shape shape) {
System.out.println("Drawing rectangle: " + shape.width + "x" + shape.height);
}
private void drawCircle(Shape shape) {
System.out.println("Drawing circle with radius: " + shape.radius);
}
private void drawTriangle(Shape shape) {
System.out.println("Drawing triangle with base: " + shape.base);
}
private void drawSquare(Shape shape) {
System.out.println("Drawing square with side: " + shape.side);
}
}