别滥用面向对象设计(OOD)中的继承:从一则简单的回调工具类的重构案例,来看OOP/OOD原则
博客园支持 mermaid 语法了,赞一个👍🏻@博客园团队💯
案例背景:支付回调系统的设计
在支付网关系统中,回调处理是核心功能之一。我们分析以下三个关键类:
classDiagram
class LevyCallback {
<<interface>>
+rechargeCallBack()
+paymentCallBack()
+signCallBack()
...
}
class LevyCallbackCommon {
+readString() static
+render() static
}
class LevyCallbackImpl {
-levyWithdrawalFlowSuccessApi
-levyPaymentSuccessApi
...
+rechargeCallBack()
+paymentCallBack()
...
}
LevyCallbackImpl --|> LevyCallbackCommon
LevyCallbackImpl ..|> LevyCallback
1. 接口定义:LevyCallback
public interface LevyCallback {
void rechargeCallBack(Long levyId, HttpServletRequest request, HttpServletResponse response);
void paymentCallBack(Long levyId, HttpServletRequest request, HttpServletResponse response);
// 其他方法省略...
}
2. 工具类:LevyCallbackCommon
public class LevyCallbackCommon {
protected LevyCallbackCommon() {}
public static String readString(HttpServletRequest request) {
try {
return CallBackKit.readReqData(request);
} catch (IOException e) {
throw new ParameterException("解析请求报文失败");
}
}
public static void render(HttpServletResponse response, String text) {
// 实现省略...
}
}
3. 核心实现类:LevyCallbackImpl
@Service
public class LevyCallbackImpl extends LevyCallbackCommon implements LevyCallback {
@Override
public void rechargeCallBack(Long levyId, HttpServletRequest request, HttpServletResponse response) {
final String rawReqData = readString(request); // 继承自LevyCallbackCommon
// 业务处理逻辑...
render(response, result.getResult()); // 继承自LevyCallbackCommon
}
// 其他方法实现省略...
}
LevyCallbackCommon的设计缺陷
1. 违反继承关系的本质
// 问题代码示例
public class LevyCallbackImpl extends LevyCallbackCommon
implements LevyCallback {
// 通过继承获得工具方法
public void rechargeCallBack(...) {
final String rawReqData = readString(request);
render(response, result.getResult());
}
}
设计问题:
- 工具类被错误地作为基类使用
- 继承关系不满足"is-a"原则
- 静态方法通过继承引入,破坏封装性
2. 破坏单一职责原则
LevyCallbackCommon
承担了双重角色:
- 作为工具类提供静态方法
- 作为父类被继承(但未提供可扩展行为)
3. 错误使用继承而非组合
LevyCallbackImpl需要工具方法。但错误地继承了LevyCallbackCommon,导致紧耦合。正确的方式是,组合调用LevyCallbackCommon,从而实现松耦合。
重构方案:遵循OOP原则的改造
方案一:独立工具类(推荐)
将LevyCallbackCommon
rename为CallbackUtils
。LevyCallbackImpl
依赖调用CallbackUtils
提供的工具方法。
public final class CallbackUtils {
private CallbackUtils() {}
public static String readString(HttpServletRequest request) {
// 实现不变...
}
public static void render(HttpServletResponse response, String text) {
// 实现不变...
}
}
// 修改后的实现类
@Service
public class LevyCallbackImpl implements LevyCallback {
@Override
public void rechargeCallBack(...) {
String data = CallbackUtils.readString(request);
// 业务逻辑...
CallbackUtils.render(response, result.getResult());
}
}
方案二:内联工具方法
@Service
public class LevyCallbackImpl implements LevyCallback {
// 私有静态工具方法
private static String readString(HttpServletRequest request) {
// 原实现...
}
private static void render(HttpServletResponse response, String text) {
// 原实现...
}
@Override
public void rechargeCallBack(...) {
String data = readString(request);
// 业务逻辑...
render(response, result.getResult());
}
}
OOP设计原则实践总结
1. 里氏替换原则(LSP)的启示
重构前问题:
LevyCallbackImpl
无法替代LevyCallbackCommon
- 工具类作为父类没有提供可替换行为
合法的OOP继承关系示例:
public abstract class AbstractCallback {
protected abstract void process();
}
public class PaymentCallback extends AbstractCallback {
@Override
protected void process() {
// 支付特定逻辑
}
}
2. 组合优于继承(Composition over Inheritance)原则
重构本质:
- 用has-a(拥有工具方法)替代is-a(是工具类)
- 通过依赖注入实现灵活组合
3. 单一职责原则(SRP)
职责划分:
LevyCallback
:定义回调契约CallbackUtils
:处理HTTP数据LevyCallbackImpl
:实现业务逻辑
4. 开闭原则(OCP)保障
// 扩展新回调处理器
public class RefundCallbackImpl implements LevyCallback {
public void rechargeCallBack(...) {
String data = CallbackUtils.readString(request);
// 新的退款处理逻辑...
}
}
最佳实践指南
- 工具类设计规范
- final类
- 私有化构造器
- 所有方法必须是静态的
public final class XxxUtils {
private XxxUtils() {} // 关键:私有构造器
// 所有方法必须是静态的
public static returnType methodName(params) {...}
}
- 继承适用性评估准则
结论:OOP思想的本质体现
通过本案例的重构,我们得到以下启示:
- 继承的本质是建立类型层级关系。继承可以实现代码复用,但不要为了代码复用而滥用继承
- 多态的基础是接口契约,不是实现继承
- 工具类的定位应该是无状态的独立助手
- 类关系的设计需要严格遵循SOLID原则
Robert C. Martin在《Clean Code》中指出:
"继承是面向对象系统中最强大的工具之一,但也是最容易被滥用的工具。除非你真正需要多态行为,否则应该优先选择组合。"
本次重构不仅解决了具体的技术债务,更演示了如何通过OOP原则构建高内聚、低耦合的系统。这种设计思维可以帮助开发者创建更健壮、更易维护的应用系统。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/19080886