如何在所有实现Sender的子类中统一执行cleanDataBeforeSend()?
问题描述
现有代码结构如下:
sender.js
function Sender () {} Sender.prototype.sendData = goog.abstractMethod;
userinfosender.js
// @implements {Sender} class UserInfoSender { ... sendData(...) {...} ... }
documentcontentsender.js
// @implements {Sender} class DocumentContentSender { ... sendData(...) {...} ... }
当前有大约20个类似xxxSender的类,希望在所有这类类中执行通用函数cleanDataBeforeSend()。如果在每个子类的sendData里手动调用这个函数,不仅繁琐,还可能导致未来新增子类时忘记调用。请问推荐的实现方式是什么?
推荐实现方案
方案1:用模板方法模式改造父类Sender
这是最稳妥的方案,通过模板方法固定sendData的执行流程,将通用逻辑和子类特有逻辑分离:
修改sender.js:
function Sender () {} // 父类定义完整的sendData执行流程 Sender.prototype.sendData = function(data) { // 强制执行通用数据清理逻辑 const cleanedData = this.cleanDataBeforeSend(data); // 交给子类实现具体的发送逻辑 return this.doSendData(cleanedData); }; // 通用清理方法,子类可按需重写自定义规则 Sender.prototype.cleanDataBeforeSend = function(data) { // 这里写统一的清理规则,比如过滤空值、规范字段格式 return Object.fromEntries( Object.entries(data).filter(([_, val]) => val != null && val !== '') ); }; // 抽象方法,子类必须实现的具体发送逻辑 Sender.prototype.doSendData = goog.abstractMethod;
所有子类只需实现doSendData,无需再自行处理sendData:
// @implements {Sender} class UserInfoSender extends Sender { doSendData(cleanedData) { // 这里写原sendData方法中的业务代码 } }
不管是现有20个子类,还是未来新增的子类,只要继承Sender并实现doSendData,就会自动触发清理逻辑,完全不会遗漏。若某个子类需要特殊清理规则,直接重写cleanDataBeforeSend即可。
方案2:用装饰器包装子类的sendData方法
如果不想改动父类结构,可以用装饰器给所有xxxSender的sendData自动加上前置清理逻辑:
先编写装饰函数:
function withDataCleaning(targetClass) { const originalSend = targetClass.prototype.sendData; // 重写sendData,先执行清理再调用原方法 targetClass.prototype.sendData = function(data) { const cleanedData = this.cleanDataBeforeSend(data); return originalSend.call(this, cleanedData); }; // 给类添加默认的通用清理方法,子类可重写 if (!targetClass.prototype.cleanDataBeforeSend) { targetClass.prototype.cleanDataBeforeSend = function(data) { // 通用清理逻辑 return Object.fromEntries( Object.entries(data).filter(([_, val]) => val != null && val !== '') ); }; } return targetClass; }
给子类应用装饰器(支持装饰器语法的环境):
// @implements {Sender} @withDataCleaning class UserInfoSender { sendData(data) { // 原业务代码保持不变 } }
若环境不支持装饰器语法,可手动包装类:
class DocumentContentSender { sendData(data) { // 原业务代码保持不变 } } // 给类添加清理逻辑包装 withDataCleaning(DocumentContentSender);
这个方案对现有代码的侵入性更低,无需调整父类结构,同样能保证所有子类自动执行清理逻辑。
内容的提问来源于stack exchange,提问作者echo Lee
相关产品推荐
相关产品推荐

