java 中通过接口实现解耦的核心做法是面向接口编程,即定义抽象契约并让具体类去实现它。在代码中,依赖方只声明接口类型的变量或参数,而不直接引用具体实现类。这样做可以将调用者与具体逻辑分离,使得在不修改调用代码的前提下替换不同的实现,从而降低模块间的耦合度。

UserService 接口如何隔离 UserServiceImpl 的变化
当业务逻辑发生变化时,只需修改实现类而无需改动调用者。例如,定义一个 UserService 接口,其中包含 getUserById 方法。创建一个 UserServiceImpl 类实现该接口。在客户端代码中,使用 UserService 类型来引用 UserServiceImpl 的实例。这样,如果未来需要更换为 FakeUserServiceImpl,只需改变实例化的一行代码,其他逻辑保持不变。

public interface UserService {
String getUserById(int id);
}
public class UserServiceImpl implements UserService {
@Override
public String getUserById(int id) {
return "User-" + id;
}
}
public class Client {
private final UserService userService;
public Client(UserService userService) {
this.userService = userService;
}
public void doWork() {
String user = userService.getUserById(1);
System.out.println(user);
}
}
上述代码展示了依赖注入的基本形式。客户端通过构造函数接收 UserService 接口的实现。运行 Client 类的 doWork 方法将输出 User-1。这种结构确保了客户端不依赖于具体的 UserServiceImpl 类,而是依赖于抽象接口。
立即学习“Java免费学习笔记(深入)”;
策略模式如何利用接口切换算法行为
策略模式允许在运行时动态切换算法。定义一个 PaymentStrategy 接口,包含 pay 方法。创建 CreditCardPayment 和 PayPalPayment 两个实现类。在订单处理类中,持有 PaymentStrategy 接口引用。根据用户选择,传入不同的支付策略实现。这种方式消除了条件判断语句,使新增支付方式变得简单。

public interface PaymentStrategy {
void pay(double amount);
}
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
public class OrderProcessor {
private final PaymentStrategy strategy;
public OrderProcessor(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void processOrder(double amount) {
strategy.pay(amount);
}
}
通过创建 OrderProcessor 实例并传入 CreditCardPayment,调用 processOrder(100.0) 将打印 Paid 100.0 via Credit Card。若传入 PayPalPayment,则行为随之改变。这体现了接口在算法层面的解耦能力。
当接口方法返回值为空字符串时如何处理
在之前的示例中,getUserById 方法始终返回非空值。但在实际场景中,可能因 ID 不存在而返回空字符串或 null。如果 UserService 的实现改为在 ID 无效时返回空字符串 "",客户端代码需要检查返回值是否为空,以避免后续操作出错。例如,在 Client 中获取用户后,应判断 user.isEmpty() 来决定是否继续处理。这种对接口返回值的防御性编程也是解耦的一部分,因为它让调用者不必关心内部是如何判断无效的。


















