C类扩展B.并且B类扩展A1或A2,具体取决于C的构造函数的参数。如何定义A,B和C类?
答案 0 :(得分:4)
由于您需要对父类(class B extends A1
)进行硬编码,这是不可能的(尽管运行时扩展/黑客,我不建议进入)。如果您需要这种灵活性,请查看composition而不是继承。
答案 1 :(得分:2)
Like deceze already points out,继承无法做到这一点。
您可以使用PECL的runkit_class_adopt
将基类转换为继承的类,在适当的时候添加祖先的方法但是runkit是您不想要的东西生产代码。
干净的OO方法是使用Bridge pattern在运行时为对象提供A类的实现,从而
将抽象与其实现分离,以便两者可以独立变化。
工作原理
首先定义B和B本身必须实现的每个“父”的接口。界面应包含您希望B“继承”的所有方法。我把这些术语放在引号中,因为从技术上讲,它们既不是父母,也不是继承任何东西。
interface MyImplementation
{
public function doSomething();
// more methods …
}
然后定义实现此接口的类A1和A2,并添加接口所需的方法。
class A1 implements MyImplementation
{
public function doSomething()
{
return 'A1';
}
// more methods …
}
class A2 implements MyImplementation
{
public function doSomething()
{
return 'A2';
}
// more methods …
}
接下来创建你的B类,并使它在初始化时需要一个实现类。
abstract class B implements MyImplementation
{
protected $_implementation;
// more properties ...
public function __construct(MyImplementation $implementationObj)
{
$this->_implementation = $implementationObj;
}
public function doSomething()
{
return $this->_implementation->doSomething();
}
// more methods ...
}
正如您所看到的,对接口所需方法的任何调用都被委托给聚合的“父”对象,因此根据您传入B的内容,您将获得不同的结果。
现在要定义C,我们只是让它接受实现类的类名,并在C中实例化它以将它传递给父类,例如乙
class C extends B {
public function __construct($bMethodImplementation) {
parent::__construct(new $bMethodImplementation);
}
}
然后你可以做
$c = new C('A1');
echo $c->doSomething(); // echoes A1
$c = new C('A2');
echo $c->doSomething(); // echoes A2