在运行时将父类分配给类?

时间:2010-11-13 07:33:14

标签: php design-patterns

C类扩展B.并且B类扩展A1或A2,具体取决于C的构造函数的参数。如何定义A,B和C类?

2 个答案:

答案 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