MST

星途 面试题库

面试题:Java中protected和default修饰符对代码可维护性和扩展性的影响及优化策略

从代码可维护性和扩展性的角度出发,分析protected和default修饰符对程序架构的影响。假设在项目后期需要对某一模块进行重构,该模块大量使用了protected和default修饰的元素,讨论如何在不破坏现有功能的前提下,优化这些修饰符的使用以提升代码的可维护性和扩展性,给出具体的优化策略和示例代码。
30.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. protected 和 default 修饰符对程序架构的影响

  • protected
    • 可维护性:protected 修饰的成员可以被同一包内的类以及不同包中的子类访问。这在一定程度上增加了代码的耦合度,因为子类对父类 protected 成员的访问可能会导致父类实现细节暴露。当父类的 protected 成员发生变化时,可能影响到多个子类,维护成本增加。
    • 扩展性:从扩展性角度看,protected 成员为子类提供了一定的扩展能力,子类可以基于这些 protected 成员进行功能扩展。但过度使用可能导致子类与父类之间的关系过于紧密,不利于系统的灵活扩展。
  • default(即包访问权限,没有修饰符时的默认情况):
    • 可维护性:default 修饰的成员只能被同一包内的类访问。这在一定程度上限制了访问范围,使得包内的类之间形成相对紧密的联系。如果包结构设计不合理,包内类对 default 成员的依赖可能导致维护困难,因为对一个类的修改可能影响到包内其他依赖它的类。
    • 扩展性:对于扩展性而言,default 修饰符限制了外部包对该类成员的访问,有利于保持包的独立性。但如果需要在不同包之间进行功能扩展,可能需要重新设计包结构或使用其他方式来暴露功能。

2. 优化策略

  • 减少 protected 使用
    • 策略:将部分 protected 成员提升为 public 并通过接口来暴露,使得子类可以通过接口来访问相关功能,减少对子类直接访问父类实现细节的依赖。同时,对于一些只在子类内部使用的逻辑,可以提取到一个单独的方法,并通过 protected 方法调用,这样父类的核心逻辑与子类扩展逻辑进一步分离。
    • 示例代码
// 定义一个接口
interface CommonFunction {
    void commonOperation();
}

// 父类实现接口
class ParentClass implements CommonFunction {
    private int data;

    // 原本的 protected 方法
    // 现在通过接口方法暴露给外部
    @Override
    public void commonOperation() {
        // 具体实现
    }

    // 提取只在子类内部使用的逻辑
    protected void internalSubclassLogic() {
        // 具体逻辑
    }
}

// 子类继承父类
class SubClass extends ParentClass {
    @Override
    public void commonOperation() {
        super.commonOperation();
        internalSubclassLogic();
    }
}
  • 优化 default 使用
    • 策略:如果不同包需要访问 default 修饰的功能,可以考虑将相关功能封装成一个服务类,并通过合适的设计模式(如工厂模式、单例模式)来提供访问入口。这样既可以保持包的相对独立性,又能在需要时为外部包提供访问途径。
    • 示例代码
// 原本包内有一个具有 default 访问权限的类
class PackageInternalClass {
    void internalFunction() {
        // 具体功能
    }
}

// 定义一个服务类,使用单例模式
class PackageService {
    private static PackageService instance;
    private PackageInternalClass internalClass;

    private PackageService() {
        internalClass = new PackageInternalClass();
    }

    public static PackageService getInstance() {
        if (instance == null) {
            instance = new PackageService();
        }
        return instance;
    }

    public void performInternalFunction() {
        internalClass.internalFunction();
    }
}

在其他包中,可以通过以下方式访问:

// 其他包中的类
class OtherPackageClass {
    public void usePackageService() {
        PackageService.getInstance().performInternalFunction();
    }
}