假设我有一个名为PageBuilder
的类,它实例化,通过我的index
文件(充当前端控制器)发送参数和调用函数。有PageBuilder
类关联的三个子类:Head
,Body
和Foot
,由PageBuilder
访问,基本上将它们抽象为{{1} }}。
所以理论上你可以实例化index
并拥有对其他类的完全访问权限,就像它们是PageBuilder
的一部分一样。
如何使用类,抽象类和接口的任意组合在PHP5中实现这样的设计?
我不认为PHP5可以实现上述功能,不一定是因为PHP有其局限性,但可能是因为我以错误的方式设计我的应用程序。
PHP中OOP的常见示例不足以帮助我理解如何构建更复杂的设计。
感谢。
答案 0 :(得分:4)
其他一些答案是正确的。您遇到的问题是您的PageBuilder
课程做得太多了。对于你正在尝试用它做的事情,这个名字听起来是错误的。 PageBuilder
听起来像是将一堆部分组合成Page
的东西。我们称这些部分为Section
。然后,你想要做的就是使用构图,正如几个答案所暗示的那样。
继承通常被描述为is-a
关系,因为如果您的Section
类扩展PageBuilder
类,则Section
是PageBuilder
。你想要的是一个has-a
关系,就像你的PageBuilder
类有一个(或很多)Section
(s)一样。任何时候你需要has-a
关系,你应该关注组合而不是继承。
所以这可能是你的类层次结构:
abstract class PageBuilder
{
//@var Section
public $header;
//@var Section
public $body;
//@var Section
public $footer;
public function render()
{
echo $this->header.$this->body.$this->footer;
}
}
class Section
{
protected $content;
}
class LoginPage
extends PageBuilder
{
public function __construct()
{
$this->header=new Section(...);
$this->footer=new Section(...);
$this->body=new Section(...);
}
}
在这一点上,你真的是通过制造一个糟糕的MVC系统来重新发明轮子。如果这是一个项目(而不是学习),你应该考虑使用PHP的一个MVC框架。 (我推荐Kohana,但有关于Stack Overflow上最好的PHP版本的several questions。)如果您正在考虑这些事情,MVC可能不会是一个很好的飞跃。
答案 1 :(得分:2)
根据我的理解,你可以使用复合模式
http://en.wikipedia.org/wiki/Composite_pattern
您的控制器索引只能访问实现接口IPageBuilder(或类似名称)的对象,其中一些标准函数类似于“generatePage”。实际上,这个对象是包含IPageBuilder类型的其他对象的某种容器。那些叶子对象将能够构建页面的一些子部分,如头部,身体和脚部。每个叶对象都是不同的类,但它们将实现IPageBuilder接口。当您的索引对象调用“generatePage”时,容器将按顺序调用其每个叶对象的“generatePage”方法,这将依次处理呈现HTML。
使用这种方法,如果您的Body类变得太大,您可以随时将其转换为实现IPageBuilder接口的容器,例如博客帖子Body可以包含Article对象和CommentList对象。然后,body对象只会将“generatePage”方法传播到其子对象。
要创建IPageBuilder对象,可以使用工厂模式
http://en.wikipedia.org/wiki/Factory_method_pattern
说实话,我过去曾尝试过这种方法来生成我的HTML并发现它们有点矫枉过正。我的建议是使用模板引擎,比如Smarty。如果那样做,你的设计师会爱你(或者更少恨你)。
如果你想知道如何在PHP中使用接口,那不是很难......
答案 2 :(得分:0)
所以如果我理解正确你想要Head,Body和Foot自动构建为PageBuilder的孩子吗?
有几种方法可以做到这一点。
1)在PageBuilder中创建变量以保存类并使用__call方法
class PageBuilder{
private _head;
private _body;
private _foot;
function __construct(){
$this->_head = new Head();
$this->_foot = new Foot();
$this->_body = new Body();
}
function __call($name, $args){
if(method_exists($this->_head, $name)) call_user_func_array(array($this->head, $name), $args);
// Repeat for other classes.
}
}
这里的问题显然是,如果两个类共享相同的方法,那么第一个出现的方法获胜。您可以修改它以便很容易地根据函数名称选择一个类。
2)将一切都束缚下来。
Abstract class Page{
}
class Head extends Page{
}
class Body extends Head{
}
class Foot extends Body{
}
class PageBuilder extends Foot{
}
无论哪种方式都有点被黑,你只需要让它发挥作用。
答案 3 :(得分:-1)
PHP只允许您扩展一个父类(它可以反过来扩展另一个父类等)。没有接口,这意味着你不能像在C ++中那样从多个接口继承函数或属性。
因此,你可能需要做更多这样的事情:
class PageBuilder {
protected Head, Body, Foot;
public function __construct($request) {
$view = $this->getView($request);
$this->Head = new PageSection('head.tpl');
$this->Body = new PageSection($view);
$this->Foot = new PageSection('foot.tpl');
}
private function getView($request) {
// @todo return the template filename/path based upon the request URL
}
}
class PageSection {
private $template;
public function __construct($template) {
$this->template = $template;
}
public function render() {
// @todo process and output the $this->template file
}
}