寻求100%类型严格的单/批量元素处理设计模式方案
100%类型严格的统一处理方案
要实现你想要的全程单一类型、无类型判断的调用方式,最优雅的做法是使用适配器模式,将原有单元素处理器适配到统一的批量处理接口上,同时让新的批量处理器直接实现这个统一接口。这样就能彻底消除类型分支,保持类型系统的严格性。
核心思路
我们需要定义一个统一的顶层接口,要求所有处理器都能接收list<Element>集合并返回字符串。对于原有只支持单元素处理的策略,我们用适配器类包裹它,把批量处理的逻辑转化为逐个调用原有单元素方法;新的批量处理器则直接实现这个统一接口,原生支持集合处理。
具体实现步骤
1. 定义统一的处理接口
这个接口是所有处理器的契约,明确要求处理list<Element>集合:
interface ElementProcessingStrategyInterface { /** * @param list<Element> $elements */ public function process(array $elements): string; }
2. 适配原有单元素处理器
创建适配器类,将原有ProcessingStrategyInterface的实现适配到新的统一接口。适配器内部会遍历元素集合,逐个调用原有单元素处理方法:
class SingleElementProcessorAdapter implements ElementProcessingStrategyInterface { public function __construct( private ProcessingStrategyInterface $singleProcessor ) {} /** * @param list<Element> $elements */ public function process(array $elements): string { // 这里保持和你原有逻辑一致:逐个处理,保留最后一个结果 $result = ''; foreach ($elements as $element) { $result = $this->singleProcessor->process($element); } return $result; } }
3. 让批量处理器实现统一接口
你的BatchProcessingStrategyInterface可以直接替换为实现统一接口(或者让它继承统一接口,保留原有方法名)。这里我们直接让批量处理器实现统一接口,保持调用一致性:
class ExampleBatchProcessor implements ElementProcessingStrategyInterface { /** * @param list<Element> $elements */ public function process(array $elements): string { // 你的批量处理逻辑,比如一次性处理所有元素 $processedValues = array_map(fn(Element $element) => $element->getContent(), $elements); return implode('|', $processedValues); } }
4. 改造Listener,使用统一接口
现在Listener只需要持有统一接口的实例,完全不需要类型判断,直接调用统一的process方法:
class SomeListener { /** * @var array<string, ElementProcessingStrategyInterface> */ protected array $processors; // 在依赖注入时完成适配器包装 public function __construct( // 原有单元素处理器 ProcessingStrategyInterface $legacySingleProcessor, // 新的批量处理器 ElementProcessingStrategyInterface $batchProcessor ) { // 用适配器包装原有单元素处理器 $this->processors['legacy-type'] = new SingleElementProcessorAdapter($legacySingleProcessor); // 批量处理器直接加入 $this->processors['batch-type'] = $batchProcessor; } public function __invoke(DocumentContent $event) { /** * @var array<string, list<Element>> $elements */ $elementGroups = $event->getDynamicElements(); foreach ($elementGroups as $type => $elements) { $processor = $this->processors[$type]; // 统一调用,完全类型安全 $result = $processor->process($elements); // 后续处理$result的逻辑... } } }
为什么这是类型严格的方案?
- 所有处理器都实现同一个接口,
$processors数组的类型提示完全精确,静态分析工具(如PHPStan、Psalm)不会报类型错误。 - 调用时无需任何
instanceof判断,完全符合你想要的统一调用方式。 - 原有单元素处理器的逻辑被完整保留,通过适配器实现了逻辑复用,没有修改原有代码(开闭原则)。
内容的提问来源于stack exchange,提问作者Zoltán Fekete
相关产品推荐
相关产品推荐

