重构和检视代码过程中,我们有时会碰到由于项目交接或者人员替换导致的代码腐化,比较常见的是类的职责不单一,此时比较好的重构技巧就是按照职责抽取函数或者类,进而还要分析一下是不是可以抽象一下,提取接口。
示例代码:
- /**
- * @author: Coline
- * @ClassName: ExtractClass
- * @Date: 2022/8/21 0:40
- * @Description: 抽取类
- * 代码坏味道: 类职责不统一
- * 1. 吃饭,喝水可以归类为一类
- * 2. 通过考试可以归类为一类
- */
- public class ExtractClass {
- public void entry(){
- eat();
- drink();
- passMathExam(true);
- passEnglishExam(false);
- }
-
- /**
- * 吃饭
- */
- public static void eat(){
- System.out.println("I am eating now");
- }
-
- /**
- * 喝水
- */
- public static void drink(){
- System.out.println("I am drinking now");
- }
-
- /**
- * 通过了数学考试
- */
- public static void passMathExam(boolean isPass){
- if (isPass){
- System.out.println("I am pass the english exam");
- } else {
- System.out.println("I am not pass the english exam");
- }
- }
-
- /**
- * 通过了英语考试
- */
- public static void passEnglishExam(boolean isPass){
- if (isPass){
- System.out.println("I am pass the math exam");
- } else {
- System.out.println("I am not pass the math exam");
- }
- }
-
- }
可以看出存在类职责不统一的情况,那我们的目标就很明确了,1. 吃饭,喝水可以归类为一类,2. 通过考试可以归类为一类,也就是说我们的目标是将eat,drink抽取到一个类中,passMathExam,passEnglishExam抽取到一个类中
在弹出框中填写迁移后的类名,勾选Create nested class(创建内部类),勾选需要迁移的方法
点击Refactor,就会将内部内创建,并将方法迁移到内部类,passMathExam,passEnglishExam方法的迁移也是类似,这里不做赘述。
在弹出框中填写要迁移到的包名
点击Refactor,如图选择
关注之前调用的地方自动发生了变化
关注原有调用的地方自动做了new实例的动作
SOLID设计原则中的开闭原则(OCP)提出软件实体(模块、类、方法等)应该“对扩展开放、对修改关闭”。
可以简单的思考一下,我们这个示例中,如果在新增一个通过了语文考试,我们是不是需要再新增一个方法,这个类逐渐就开始有腐化的味道了,可扩展性不好,违反了OCP原则。因此,我们可以考虑把考试通过情况抽象为一个接口,利用Java的多态处理考试通过情况。
下图是此时考试情况的类详情:
在弹出框输入接口名,接口所在包位置,需要抽取的接口函数
选择Refactor后就会自动创建包和接口,这里有一点需要注意,IDEA没有办法自动识别到另一个类也是可以实现这个接口的,需要手动处理。
接口抽取完成后,调用时常见的时间就可以使用设计模式的工厂模式处理调用逻辑,新增考试科目就只需实现接口,修改工厂类即可,减少业务层修改,做好代码分层,受限于篇幅就不在这里赘述了。