You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在所有实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 03:23:27