重构手法——对象结构优化类 | 集成体系重构 | 合并层级结构

简介

"合并层次结构"(Collapse Hierarchy)是一种重构手法,适用于当类层次结构过于复杂,存在一些子类或父类没有足够的存在价值时,通过将它们合并,简化类的结构,提高代码的可维护性和可读性。

针对的症状(代码坏味道)

  • 类层次结构过深:存在过多的类继承层级,导致代码理解和维护困难。
  • 子类或父类功能过少:部分子类或父类只有很少的方法或属性,没有充分体现其存在的意义。

合并层次结构(Collapse Hierarchy)的详细步骤

  1. 识别可合并的类
    • 寻找功能相似的类:在类层次结构中,找到那些功能大部分重叠的子类和父类。
    • 检查类的独特性:确定哪些类的独特功能很少,大部分行为都与其他类重复。
  2. 选择合并方式
    • 向上合并:如果子类的独特功能很少,大部分行为都在父类中,可将子类的独特功能移到父类,然后删除子类。
    • 向下合并:若父类功能较少,而子类有较多共同行为,可将父类的属性和方法移到子类,然后删除父类。
  3. 移动成员
    • 根据选择的合并方式,将需要移动的属性和方法从一个类移动到另一个类。
    • 确保移动后的代码逻辑正确,所有依赖关系都得到妥善处理。
  4. 更新引用
    • 检查代码中所有对被合并类的引用,将其更新为对合并后类的引用。
    • 这包括构造函数调用、方法调用等各种引用。
  5. 测试
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
    • 手动测试:如果有必要,进行手动测试以验证功能的正确性。
  6. 代码审查
    • 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性得到提升。
    • 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明合并层次结构的影响。

示例

假设有一个简单的图形绘制类层次结构,如下:

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的方法,功能较少。CircleSquare类大部分功能依赖于Shape类,且 Shape类没有太多独特功能。这里可以考虑向上合并。

步骤如下:

  1. 识别可合并的类Shape类功能相对较少,可考虑将其与CircleSquare类合并。

  2. 选择合并方式:向上合并。

  3. 移动成员 :将Shape类的color属性和getColor方法移动到CircleSquare类中。

    java 复制代码
       class 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;
        }
    }
  4. 更新引用 :如果有代码创建Shape对象并使用其属性或方法,需更新为创建CircleSquare对象并使用新的结构。

  5. 测试

    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
  6. 代码审查:让同事审查代码,确保没有引入新的问题。

练习

基础练习题

  1. 简单类层次结构合并

    • 给定以下 Java 代码,Animal类作为父类,DogCat类作为子类,Animal类功能较少。请将Animal类与DogCat类进行合并。

      java 复制代码
            class 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.");
          }
      }
  2. 属性和方法移动合并

    • 下面的 Java 代码中,Vehicle类作为父类,CarTruck类作为子类,Vehicle类只有一个speed属性和获取speed的方法。请将 Vehicle类与CarTruck类合并,并合理移动属性和方法。

      java 复制代码
        class 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;
          }
      }

进阶练习题

  1. 复杂类层次结构合并与依赖处理

    • 在这段 Java 代码中,Employee类作为父类,ManagerDeveloper类作为子类,Employee类有一些通用方法和属性, ManagerDeveloper类有一些独特方法。但Employee类部分功能与子类重叠较多。请进行合理的合并层次结构重构,并处理好方法之间的依赖关系。

      java 复制代码
        class 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 + ".");
          }
      }
  2. 合并层次结构与多态处理

    • 给定以下 Java 代码,Shape类作为父类,RectangleTriangle类作为子类,Shape类有一个draw 方法,子类重写了该方法。请进行合并层次结构重构,同时确保多态性仍然能够正确实现。

      java 复制代码
        abstract 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.");
         }
      }

综合拓展练习题

  1. 多模块合并层次结构与代码审查模拟
    • 考虑一个简单的 Java 学校管理系统,有Person类作为父类,StudentTeacherStaff类作为子类。Person 类有一些通用的属性和方法,如nameageprintInfo方法。Student类有studentIdenrollCourse方法,Teacher类有 teacherIdteachCourse方法,Staff类有staffIdperformDuty方法。部分功能在类之间存在重叠。

    • 请对这些类进行 "合并层次结构" 重构,合理简化类的层次结构。

    • 假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。

      java 复制代码
        class 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 + ".");
         }
      }
相关推荐
程序员爱钓鱼25 分钟前
Rust 开发环境安装(Windows|macOS|Linux)
后端·rust
爱勇宝9 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒13 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码14 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo14 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志15 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..15 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects15 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰15 小时前
一些基础和问题解决
后端
陈随易16 小时前
前端项目部署只要30秒
前端·后端·程序员