本文介绍如何利用接口继承与组合解决多职责类无法统一实现同一接口的问题,通过定义细粒度接口并组合使用,确保代码既符合开闭原则,又支持类型安全的依赖注入。
在面向对象设计中,接口的核心价值在于声明契约——它不规定“你是谁”,而明确“你能做什么”。当一个类(如 LogUserService)需要同时具备日志记录(log())和属性设置(setAttr())两种能力,但另一同类(如 LogDownloadService)仅需前者时,强行让所有类实现同一宽泛接口(如 SystemLogInterface)会违背接口隔离原则(ISP),导致调用方被迫依赖未使用的方法,或因缺失方法而编译失败。
正确的做法是采用接口拆分 + 组合策略:
1. 定义原子级职责接口
首先将不同职责抽象为独立接口,确保单一、正交:
interface SystemLogInterface
{
public function log(string $type): void;
}
interface AttributeConfigurableInterface
{
public function setAttr(mixed $value): void;
}
2. 创建组合接口(可选,提升语义清晰度)
若某类需同时满足两类契约,可定义组合接口,显式表达其复合能力:
interface LoggableWithAttributesInterface extends SystemLogInterface, AttributeConfigurableInterface
{
// 空接口,仅作类型标记(PHP 支持多重继承接口)
}
3. 各类按需实现对应接口
-
LogDownloadService 仅实现基础日志能力: