如何在PieClass与ClassModel场景中应用适配器模式?
用适配器模式解决PieClass与ClassModel的数据格式兼容问题
咱们先把问题拆解清楚:
PieClass::setData()要求传入的$data是每个元素都带id属性的对象数组,它会把这些对象按id作为键重新整理成数组。ClassModel::data()返回的是依赖注入的模型查询结果,这个结果的格式大概率和PieClass要求的不匹配(比如可能是Eloquent集合、关联数组,或者是没有id属性的自定义对象)。
适配器模式的核心就是做一个"格式转换器",把ClassModel的输出转换成PieClass能识别的格式,同时不用修改原有两个类的代码(符合开闭原则)。下面是具体实现步骤:
1. 定义适配器接口(可选但推荐)
先定义一个统一的适配器接口,规范适配器需要提供的功能,方便后续扩展不同类型的模型适配器:
interface PieDataAdapterInterface { /** * 返回PieClass能接受的格式化数据 * @return object[] 每个元素带id属性的对象数组 */ public function getFormattedData(): array; }
2. 实现具体的模型适配器
创建一个针对ClassModel的适配器类,它接收ClassModel实例,负责把模型查询结果转换成PieClass需要的格式。这里假设ClassModel返回的是关联数组(如果是其他格式,调整转换逻辑即可):
class ClassModelToPieAdapter implements PieDataAdapterInterface { private $classModel; public function __construct(ClassModel $classModel) { $this->classModel = $classModel; } public function getFormattedData(): array { // 先获取ClassModel的原始数据 $rawData = $this->classModel->data(); // 把原始数据转换成PieClass需要的带id属性的对象数组 $formattedData = []; foreach ($rawData as $item) { // 如果原始是关联数组,转成stdClass对象;如果是对象但没有id,就给它加id属性 $obj = is_array($item) ? (object)$item : $item; // 确保对象有id属性(如果原始数据的id字段叫其他名字,比如'uid',这里可以映射) if (!property_exists($obj, 'id')) { $obj->id = $obj->uid; // 示例:如果原始id字段是uid,这里做映射 } $formattedData[] = $obj; } return $formattedData; } }
3. 实际使用适配器
现在就可以通过适配器把ClassModel的数据传给PieClass了,完全不用修改原有两个类的代码:
// 1. 实例化模型(比如Eloquent模型) $userModel = new UserModel(); // 假设这是依赖注入的任意模型 // 2. 实例化ClassModel $classModel = new ClassModel($userModel); // 3. 用适配器转换格式 $adapter = new ClassModelToPieAdapter($classModel); $formattedData = $adapter->getFormattedData(); // 4. 传给PieClass的setData方法 $pieClass = new PieClass(); $pieClass->setData($formattedData);
为什么这是适配器模式?
- 目标接口:PieClass的setData方法要求的数据格式就是我们的目标。
- 适配者:ClassModel是我们需要适配的现有类,它的输出不符合目标要求。
- 适配器:ClassModelToPieAdapter就是中间层,把适配者的输出转换成目标接口能接受的格式。
这种方式的好处是:如果后续换了其他模型,只需要新增对应的适配器类实现PieDataAdapterInterface即可,原有代码完全不用改动,扩展性很强。
内容的提问来源于stack exchange,提问作者Karabah
相关产品推荐
相关产品推荐

