简介
"合并层次结构"(Collapse Hierarchy)是一种重构手法,适用于当类层次结构过于复杂,存在一些子类或父类没有足够的存在价值时,通过将它们合并,简化类的结构,提高代码的可维护性和可读性。
针对的症状(代码坏味道)
- 类层次结构过深:存在过多的类继承层级,导致代码理解和维护困难。
- 子类或父类功能过少:部分子类或父类只有很少的方法或属性,没有充分体现其存在的意义。
合并层次结构(Collapse Hierarchy)的详细步骤
- 识别可合并的类
- 寻找功能相似的类:在类层次结构中,找到那些功能大部分重叠的子类和父类。
- 检查类的独特性:确定哪些类的独特功能很少,大部分行为都与其他类重复。
- 选择合并方式
- 向上合并:如果子类的独特功能很少,大部分行为都在父类中,可将子类的独特功能移到父类,然后删除子类。
- 向下合并:若父类功能较少,而子类有较多共同行为,可将父类的属性和方法移到子类,然后删除父类。
- 移动成员
- 根据选择的合并方式,将需要移动的属性和方法从一个类移动到另一个类。
- 确保移动后的代码逻辑正确,所有依赖关系都得到妥善处理。
- 更新引用
- 检查代码中所有对被合并类的引用,将其更新为对合并后类的引用。
- 这包括构造函数调用、方法调用等各种引用。
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
- 手动测试:如果有必要,进行手动测试以验证功能的正确性。
- 代码审查
- 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性得到提升。
- 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明合并层次结构的影响。
示例
假设有一个简单的图形绘制类层次结构,如下:
java
class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
public String getColor() {
return color;
}
}
class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
public double getRadius() {
return radius;
}
}
class Square extends Shape {
private double sideLength;
public Square(String color, double sideLength) {
super(color);
this.sideLength = sideLength;
}
public double getSideLength() {
return sideLength;
}
}
在这个例子中,Shape
类只有一个color
属性和获取color
的方法,功能较少。Circle
和Square
类大部分功能依赖于Shape
类,且 Shape
类没有太多独特功能。这里可以考虑向上合并。
步骤如下:
-
识别可合并的类 :
Shape
类功能相对较少,可考虑将其与Circle
和Square
类合并。 -
选择合并方式:向上合并。
-
移动成员 :将
Shape
类的color
属性和getColor
方法移动到Circle
和Square
类中。javaclass Circle { private String color; private double radius; public Circle(String color, double radius) { this.color = color; this.radius = radius; } public String getColor() { return color; } public double getRadius() { return radius; } } class Square { private String color; private double sideLength; public Square(String color, double sideLength) { this.color = color; this.sideLength = sideLength; } public String getColor() { return color; } public double getSideLength() { return sideLength; } }
-
更新引用 :如果有代码创建
Shape
对象并使用其属性或方法,需更新为创建Circle
或Square
对象并使用新的结构。 -
测试:
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
-
代码审查:让同事审查代码,确保没有引入新的问题。
练习
基础练习题
-
简单类层次结构合并
-
给定以下 Java 代码,
Animal
类作为父类,Dog
和Cat
类作为子类,Animal
类功能较少。请将Animal
类与Dog
和Cat
类进行合并。javaclass Animal { protected String name; public Animal(String name) { this.name = name; } public String getName() { return name; } } class Dog extends Animal { public Dog(String name) { super(name); } public void bark() { System.out.println(name + " is barking."); } } class Cat extends Animal { public Cat(String name) { super(name); } public void meow() { System.out.println(name + " is meowing."); } }
-
-
属性和方法移动合并
-
下面的 Java 代码中,
Vehicle
类作为父类,Car
和Truck
类作为子类,Vehicle
类只有一个speed
属性和获取speed
的方法。请将Vehicle
类与Car
和Truck
类合并,并合理移动属性和方法。javaclass Vehicle { protected int speed; public Vehicle(int speed) { this.speed = speed; } public int getSpeed() { return speed; } } class Car extends Vehicle { private int numDoors; public Car(int speed, int numDoors) { super(speed); this.numDoors = numDoors; } public int getNumDoors() { return numDoors; } } class Truck extends Vehicle { private int loadCapacity; public Truck(int speed, int loadCapacity) { super(speed); this.loadCapacity = loadCapacity; } public int getLoadCapacity() { return loadCapacity; } }
-
进阶练习题
-
复杂类层次结构合并与依赖处理
-
在这段 Java 代码中,
Employee
类作为父类,Manager
和Developer
类作为子类,Employee
类有一些通用方法和属性,Manager
和Developer
类有一些独特方法。但Employee
类部分功能与子类重叠较多。请进行合理的合并层次结构重构,并处理好方法之间的依赖关系。javaclass Employee { protected String name; protected int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } public String getName() { return name; } public int getSalary() { return salary; } public void printDetails() { System.out.println("Name: " + name + ", Salary: " + salary); } } class Manager extends Employee { private int numSubordinates; public Manager(String name, int salary, int numSubordinates) { super(name, salary); this.numSubordinates = numSubordinates; } public int getNumSubordinates() { return numSubordinates; } public void manageTeam() { System.out.println(name + " is managing a team of " + numSubordinates + " subordinates."); } } class Developer extends Employee { private String programmingLanguage; public Developer(String name, int salary, String programmingLanguage) { super(name, salary); this.programmingLanguage = programmingLanguage; } public String getProgrammingLanguage() { return programmingLanguage; } public void writeCode() { System.out.println(name + " is writing code in " + programmingLanguage + "."); } }
-
-
合并层次结构与多态处理
-
给定以下 Java 代码,
Shape
类作为父类,Rectangle
和Triangle
类作为子类,Shape
类有一个draw
方法,子类重写了该方法。请进行合并层次结构重构,同时确保多态性仍然能够正确实现。javaabstract class Shape { public abstract void draw(); } class Rectangle extends Shape { @Override public void draw() { System.out.println("Drawing a rectangle."); } } class Triangle extends Shape { @Override public void draw() { System.out.println("Drawing a triangle."); } }
-
综合拓展练习题
- 多模块合并层次结构与代码审查模拟
-
考虑一个简单的 Java 学校管理系统,有
Person
类作为父类,Student
、Teacher
和Staff
类作为子类。Person
类有一些通用的属性和方法,如name
、age
和printInfo
方法。Student
类有studentId
、enrollCourse
方法,Teacher
类有teacherId
、teachCourse
方法,Staff
类有staffId
、performDuty
方法。部分功能在类之间存在重叠。 -
请对这些类进行 "合并层次结构" 重构,合理简化类的层次结构。
-
假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。
javaclass Person { protected String name; protected int age; public Person(String name, int age) { this.name = name; this.age = age; } public void printInfo() { System.out.println("Name: " + name + ", Age: " + age); } } class Student extends Person { private int studentId; public Student(String name, int age, int studentId) { super(name, age); this.studentId = studentId; } public void enrollCourse(String course) { System.out.println(name + " with ID " + studentId + " is enrolling in " + course + "."); } } class Teacher extends Person { private int teacherId; public Teacher(String name, int age, int teacherId) { super(name, age); this.teacherId = teacherId; } public void teachCourse(String course) { System.out.println(name + " with ID " + teacherId + " is teaching " + course + "."); } } class Staff extends Person { private int staffId; public Staff(String name, int age, int staffId) { super(name, age); this.staffId = staffId; } public void performDuty(String duty) { System.out.println(name + " with ID " + staffId + " is performing " + duty + "."); } }
-