You need to enable JavaScript to run this app. PHP REST API数据对象版本化的设计模式选型,现有Mapper类臃肿可否用工厂模式优化
优惠活动
大模型
产品
解决方案
定价
更多

PHP REST API数据对象版本化的设计模式选型,现有Mapper类臃肿可否用工厂模式优化

API版本化数据对象的解耦实现方案

你原有的单一大Mapper类的问题,本质是把跨版本的字段映射、类型判断、兼容逻辑全耦合在同一个类中,随着版本迭代必然会出现代码臃肿、改动风险高的问题。这种场景下完全可以结合工厂模式做分层解耦,根本不需要把所有兼容逻辑堆在单个类里。

核心实现思路

首先要拆分职责边界,不要让业务层直接处理各个对外版本的Car对象:

  1. 先定义一套业务层通用的内部领域模型,作为所有版本对象转换的统一出口,这个模型不随对外API版本变化,只承载业务实际需要处理的字段
    示例代码:
    // 业务层统一使用的内部Car领域模型,和对外API版本完全解耦
    class InternalCarDomainModel {
      protected $color;
      protected $brand;
      protected $price;
      protected $legacyCustomField; // 兼容v1的custom字段,业务侧统一命名
      protected $exhaustConfig; // 对应v2的exhaust字段
      // 通用getter/setter方法
    }
    
  2. 把每个版本的字段映射逻辑从统一Mapper中拆出,做成单版本专属的转换器,每个转换器只负责对应一个版本的Car对象和内部领域模型的双向转换,不掺杂其他版本的逻辑
    所有转换器实现统一接口,保证方法签名一致:
    interface CarVersionConverter {
      public function toDomainModel(object $versionedCar): InternalCarDomainModel;
    }
    
    // 仅处理v1版本的转换逻辑
    class CarV1Converter implements CarVersionConverter {
      public function toDomainModel(object $v1Car): InternalCarDomainModel {
        $domain = new InternalCarDomainModel();
        $domain->color = $v1Car->color;
        $domain->brand = $v1Car->brand;
        $domain->price = $v1Car->price;
        $domain->legacyCustomField = $v1Car->custom;
        return $domain;
      }
    }
    
    // 仅处理v2版本的转换逻辑
    class CarV2Converter implements CarVersionConverter {
      public function toDomainModel(object $v2Car): InternalCarDomainModel {
        $domain = new InternalCarDomainModel();
        $domain->color = $v2Car->color;
        $domain->brand = $v2Car->brand;
        $domain->price = $v2Car->price;
        $domain->exhaustConfig = $v2Car->exhaust;
        return $domain;
      }
    }
    
  3. 引入简单工厂模式负责转换器的实例路由,工厂本身不写任何字段映射逻辑,只根据传入的对象类型返回对应的转换器实例
    示例工厂代码:
    class CarConverterFactory {
      // 提前维护版本类和转换器的映射关系,后续新增版本只需要在此处追加配置
      private array converterMap = [
        CarV1::class => CarV1Converter::class,
        CarV2::class => CarV2Converter::class
      ];
    
      public function getConverter(object $versionedCar): CarVersionConverter {
        $converterClass = $this->converterMap[get_class($versionedCar)] 
          ?? throw new Exception("暂不支持该版本的Car对象");
        return new $converterClass();
      }
    }
    

方案优势

  • 彻底消除原Mapper类中长串的if ($object instanceof CarX)判断分支,每个版本的转换逻辑独立成类,单个类的代码量极低,维护成本大幅下降
  • 完全符合开闭原则:后续新增v3版本的Car对象时,只需要新增对应的CarV3Converter实现映射逻辑,在工厂的映射表中加一行配置即可,不需要改动其他已有版本的代码,不会出现修改老逻辑引发的线上问题
  • 业务层完全不需要感知当前处理的对象属于哪个API版本,只需要通过工厂拿到对应转换器,调用统一的toDomainModel方法就能拿到业务可直接处理的通用领域模型,版本兼容逻辑和业务逻辑完全隔离

注意:这里的工厂模式仅用于路由对应版本的转换器,不要把工厂做成所有版本Car类的实例化入口,否则还是会回到类臃肿的原始问题上。


内容的提问来源于stack exchange,提问作者G-Wak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 09:45:08