带不同参数的接口方法适配:用户表单参数如何处理?
科目分组算法的参数适配方案优化
我需要将科目分配至特定分组,存在多种算法可实现该功能,但这些算法的randomize方法需要的参数各不相同,示例代码如下:
interface Algorithm { randomize(???) : int } class A implements Algorithm { randomize(int, int) : int } class B implements Algorithm { randomize(int, int, string) : int }
我提出了一个初步解决方案:给Algorithm接口新增setup()方法,通过抽象类Configurer统一管理参数,结构如下:
abstract class Configurer { private function __construct(); // 从数据库加载对应科目的参数 init(int $subjectId) : Configurer setup(Algorithm) : void; } interface Algorithm { randomize() : int setup(Configurer) : void isConfigured() : bool }
这个方案解决了数据库参数的加载问题,但我不确定该如何处理用户通过表单传入的额外参数——是否应该把表单参数以数组形式传入Configurer::init()?
针对表单参数的处理建议
你的Configurer抽象类已经承担了数据库参数的加载职责,把表单参数整合进去是合理的,但直接传数组会丢失类型约束,建议做以下优化:
扩展
init方法的参数:在init中新增表单参数的参数位,同时接收科目ID和表单提交的参数:abstract class Configurer { private function __construct(); // 同时接收科目ID和表单参数 public function init(int $subjectId, array $formParams): Configurer public abstract function setup(Algorithm $algorithm): void; }在具体Configurer实现类中校验参数:不同算法对应的
Configurer子类可以针对性校验表单参数的合法性,比如算法B需要的字符串类型参数,就在BConfigurer里做格式检查,避免无效参数流入算法。算法内部只依赖Configurer注入的参数:保持
Algorithm的randomize方法无参数,所有需要的参数(数据库+表单)都通过setup从Configurer注入,让算法只专注于分组逻辑,不用关心参数来源。
另外可以给Configurer增加统一的参数获取方法,让算法按需获取所需参数,更符合封装原则,调整后的完整示例:
abstract class Configurer { private function __construct(); protected array $dbParams; protected array $formParams; public function init(int $subjectId, array $formParams): Configurer { // 从数据库加载对应科目参数赋值给$this->dbParams $this->formParams = $formParams; return $this; } public abstract function setup(Algorithm $algorithm): void; // 统一的参数获取逻辑,优先取表单参数,再取数据库参数 protected function getParam(string $key, mixed $default = null): mixed { return $this->formParams[$key] ?? $this->dbParams[$key] ?? $default; } } class BConfigurer extends Configurer { public function setup(Algorithm $algorithm): void { if ($algorithm instanceof B) { // 按需获取算法B需要的参数 $minSize = $this->getParam('min_group_size'); $maxSize = $this->getParam('max_group_size'); $groupPrefix = $this->getParam('group_prefix'); $algorithm->setParams($minSize, $maxSize, $groupPrefix); } } } interface Algorithm { public function randomize(): int; public function setup(Configurer $configurer): void; public function isConfigured(): bool; } class B implements Algorithm { private int $minSize; private int $maxSize; private string $prefix; private bool $configured = false; public function setup(Configurer $configurer): void { if ($configurer instanceof BConfigurer) { $configurer->setup($this); $this->configured = true; } } public function setParams(int $min, int $max, string $prefix): void { $this->minSize = $min; $this->maxSize = $max; $this->prefix = $prefix; } public function isConfigured(): bool { return $this->configured; } public function randomize(): int { // 实现具体分组逻辑 return rand($this->minSize, $this->maxSize); } }
这种处理方式的优势:
- 表单参数和数据库参数统一由
Configurer管理,算法无需关心参数来源 - 不同算法的参数校验、注入逻辑隔离在各自的
Configurer子类中,符合单一职责原则 - 保持
Algorithm接口的简洁性,避免参数差异导致接口混乱
内容的提问来源于stack exchange,提问作者Boorsuk
相关产品推荐
相关产品推荐

