我正在寻找一种好的,干净的方式来解决PHP5仍然不支持多重继承的事实。这是类层次结构:
消息
- TextMessage
-------- InvitationTextMessage
- EmailMessage
-------- InvitationEmailMessage
两种类型的邀请*类有很多共同之处;我希望有一个共同的父母类,邀请,他们都会继承。不幸的是,它们与当前的祖先有很多共同点...... TextMessage和EmailMessage。这里有多重继承的经典愿望。
解决问题的最轻量级方法是什么?
谢谢!
答案 0 :(得分:142)
Alex,大多数时候你需要多重继承是一个信号,你的对象结构有点不正确。在你概述的情况下,我发现你的课堂责任太宽泛了。如果Message是应用程序业务模型的一部分,则不应该关注呈现输出。相反,您可以拆分责任并使用MessageDispatcher发送使用text或html后端传递的Message。我不知道你的代码,但让我用这种方式模拟它:
$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <jdoe@yahoo.com>';
$m->to = 'Random Hacker <rh@gmail.com>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');
$d = new MessageDispatcher();
$d->dispatch($m);
这样您可以为Message类添加一些特化:
$htmlIM = new InvitationHTMLMessage(); // html type, subject and body configuration in constructor
$textIM = new InvitationTextMessage(); // text type, subject and body configuration in constructor
$d = new MessageDispatcher();
$d->dispatch($htmlIM);
$d->dispatch($textIM);
请注意,MessageDispatcher将根据传递的Message对象中的type
属性决定是以HTML格式还是纯文本格式发送。
// in MessageDispatcher class
public function dispatch(Message $m) {
if ($m->type == 'text/plain') {
$this->sendAsText($m);
} elseif ($m->type == 'text/html') {
$this->sendAsHTML($m);
} else {
throw new Exception("MIME type {$m->type} not supported");
}
}
总结一下,责任分为两类。消息配置在InvitationHTMLMessage / InvitationTextMessage类中完成,发送算法委托给调度程序。这称为策略模式,您可以在其上阅读更多内容here。
答案 1 :(得分:14)
也许你可以用'has-a'关系替换'is-a'关系?邀请可能有一条消息,但它不一定需要'is-a'消息。邀请函可能会得到确认,但与消息模型的搭配并不顺利。
如果您需要了解更多信息,请搜索“构图与继承”。
答案 2 :(得分:9)
如果我能引用菲尔this thread ...
PHP与Java一样,不支持多重继承。
进入PHP 5.4将traits尝试提供解决方案 这个问题。
与此同时,您最好重新考虑您的课堂设计。您 如果您正在使用扩展API,则可以实现多个接口 你的课程。
还有克里斯......
PHP并不真正支持多重继承,但有一些 (有点凌乱)实现它的方法。查看一些此URL 示例:
http://www.jasny.net/articles/how-i-php-multiple-inheritance/
认为他们都有有用的链接。迫不及待想要尝试特征或者某些混合......
答案 3 :(得分:6)
Symfony框架有一个mixin plugin for this,您可能想要查看它 - 即使只是想法,如果不使用它。
“设计模式”的答案是将共享功能抽象为单独的组件,并在运行时进行组合。考虑一种方法来将邀请功能抽象为一个类,它以除了继承之外的某种方式与您的Message类相关联。
答案 4 :(得分:4)
我在PHP 5.4中使用特征作为解决此问题的方法。 http://php.net/manual/en/language.oop5.traits.php
这允许使用extends进行经典继承,但也可以将常用功能和属性放入“特征”中。正如手册所说:
Traits是一种在单继承语言(如PHP)中重用代码的机制。 Trait旨在通过使开发人员能够在生活在不同类层次结构中的几个独立类中自由地重用方法集来减少单个继承的某些限制。
答案 5 :(得分:3)
听起来decorator pattern可能是合适的,但如果没有更多细节则很难说清楚。
答案 6 :(得分:3)
这既是一个问题,也是一个解决方案......
神奇的_ 调用(), _get(),__ set()方法怎么样?我还没有测试过这个解决方案但是如果你创建了一个multiInherit类怎么办。子类中的受保护变量可以包含要继承的类数组。多接口类中的构造函数可以创建每个要继承的类的实例,并将它们链接到私有属性,比如_ext。 __call()方法可以在_ext数组中的每个类上使用method_exists()函数来定位要调用的正确方法。 __get()和__set可用于定位内部属性,或者如果您的具有引用的专家可以使子类的属性和继承的类是对相同数据的引用。对象的多重继承对使用这些对象的代码是透明的。此外,只要_ext数组按类名索引,内部对象就可以直接访问继承的对象。我已经设想创建这个超级类并且还没有实现它,因为我觉得如果它有效可能会导致一些不同的编程习惯。
答案 7 :(得分:1)
我有几个问题需要澄清你在做什么:
1)您的消息对象只是是否包含消息,例如身体,接收者,安排时间? 2)您打算如何处理您的邀请对象?与EmailMessage相比,是否需要进行特殊处理? 3)如果是这样有什么特别之处呢? 4)如果是这种情况,为什么消息类型需要以不同方式处理邀请? 5)如果您想发送欢迎信息或确认信息怎么办?它们也是新物体吗?
听起来好像你正在尝试将太多功能组合到一组对象中,这些对象只应关注保留消息内容 - 而不是如何处理它。对我来说,你看,邀请或标准信息之间没有区别。如果邀请需要特殊处理,那么这意味着应用程序逻辑而不是消息类型。
例如:我构建的系统有一个共享的基本消息对象,该对象已扩展为SMS,电子邮件和其他消息类型。但是:这些没有进一步扩展 - 邀请消息只是通过电子邮件类型的消息发送的预定义文本。特定的邀请应用程序将关注邀请的验证和其他要求。毕竟,您要做的就是将消息X发送给收件人Y,收件人Y本身应该是一个独立的系统。
答案 8 :(得分:0)
像Java一样的问题。尝试使用带抽象函数的接口来解决这个问题
答案 9 :(得分:0)
PHP确实支持接口。根据您的使用情况,这可能是一个不错的选择。
答案 10 :(得分:-1)
Message类正下方的Invitation类怎么样?
所以层次结构如下:
消息
---邀请函
------ TextMessage
------ EmailMessage
在Invitation类中,添加InvitationTextMessage和InvitationEmailMessage中的功能。
我知道邀请实际上不是一种消息,它更像是Message的功能。所以我不确定这是否是好的OO设计。