多活动类同名事件方法参数不一致适用的设计模式有哪些?
针对这个场景,推荐两种落地方案,优先选择事件上下文封装 + 接口约束的方案,是最符合设计规范且可维护性最高的实现。
方案1:事件上下文封装 + 接口约束(推荐)
核心思路是把每个事件的所有可能参数封装为独立的上下文对象,接口仅约束方法接收对应上下文类型,这样既满足接口签名统一的要求,又能让不同活动类按需从上下文取自己需要的参数,不需要的参数直接忽略即可。
示例代码:
// 定义首购事件上下文,包含所有场景可能用到的参数 class FirstPurchaseContext { public function __construct( public ?string $arg1 = null, public ?string $arg2 = null, public User $user, public ?Model $model = null, public ?int $abc = null ) {} } // 定义首交易事件上下文 class FirstTradeContext { public function __construct( public ?float $price = null, public ?mixed $something = null, public ?User $user = null, public ?Model $model = null ) {} } // 定义活动接口,约束必须实现的事件方法,签名统一 interface CampaignInterface { public function onFirstPurchase(FirstPurchaseContext $context): void; public function onFirstTrade(FirstTradeContext $context): void; } // 实现活动类,按需取参数即可 class FirstCampaign implements CampaignInterface { public function onFirstPurchase(FirstPurchaseContext $context): void { // 只取自己需要的 $context->arg1、$context->arg2、$context->user } public function onFirstTrade(FirstTradeContext $context): void { // 只取自己需要的 $context->price、$context->something、$context->user、$context->model } } class SecondCampaign implements CampaignInterface { public function onFirstPurchase(FirstPurchaseContext $context): void { // 只取 $context->user } public function onFirstTrade(FirstTradeContext $context): void { // 只取 $context->model } }
这个方案的优势:
- 完全满足接口强约束,语法层面即可保证所有活动类都实现了要求的事件方法
- 类型安全,所有参数都有明确类型提示,开发体验好,不会出现可变参数不知道传了啥的问题
- 后续新增参数只需要修改上下文类,不需要调整所有活动类的方法签名,扩展性强
- 触发事件的位置只需要统一构建上下文对象传入即可,不需要感知不同活动类的参数差异
方案2:语法外校验方案(仅适合不想调整现有参数结构的旧项目)
PHP原生接口/抽象类的方法约束必须要求参数签名完全一致,如果一定要保留不同类的事件方法参数不同,就不能用语法层面的接口约束,改用校验机制保证规则落地:
- 定义空的标识接口
CampaignInterface用来标识所有活动类 - 用单元测试批量扫描所有实现了标识接口的类,通过反射检查是否存在
onFirstPurchase、onFirstTrade方法,不管参数签名 - 也可以在活动类注册的逻辑里增加运行时反射校验,不符合要求的类直接抛出异常拦截
这种方案的劣势是失去了语法层面的强约束,必须依赖校验规则才能保证规范落地,不推荐新项目使用。
内容的提问来源于stack exchange,提问作者Pejman
相关产品推荐
相关产品推荐

