我正在尝试设计一些类层次结构,并且我在这部分“陷入困境”。
让我们说我有以下课程
abstract class Video
{
const TYPE_MOVIE = 1;
const TYPE_SHOW = 2;
abstract public function getTitle();
abstract public function getType();
}
class Movie extends Video
{
// ...
public function getType()
{
return self::TYPE_MOVIE;
}
}
class Show extends Video
{
// ...
public function getType()
{
return self::TYPE_SHOW;
}
}
在系统的不同部分,我有(Parser)类封装了创建 电影和节目对象并返回obj。给客户。
问题:获取某种类型的obj的最佳方法是什么。从解析器/工厂类返回,以便客户端可以执行类似
的操作$video = $parser->getVideo('Dumb and Dumber');
echo $video->getTitle();
// Way 1
if($video->getType == 'show') {
echo $video->getNbOfSeasons();
}
// Way 2
if($video instanceof Show) {
echo $video->getNbOfSeasons();
}
// Current way
if($video->getType == Video::TYPE_SHOW) {
echo $video->getNbOfSeasons();
}
有没有比我的解决方案更好的方法(读作:我的解决方案是否很糟糕?)?
答案 0 :(得分:2)
我会选择方式2.它会向您抽象需要在Video
添加另一个常量,以防您想要添加class SoapOpera extends Show
(例如)。
使用方式#2,您对常量的依赖性较小。无论在没有硬编码的情况下都可以获得什么信息,意味着将来可能发生的问题更少,以防您需要扩展。阅读 Tight an Loose Coupling 。
答案 1 :(得分:2)
有没有比我的解决方案更好的方法(读作:我的解决方案是否很糟糕?)?
你的解决方案本身并不糟糕。但是,每当有人试图确定子类型以执行某些操作时,我都会怀疑;为什么?这个答案可能有点理论上,甚至可能有点迂腐,但这里也是如此。
你不应该关心。父类和子类之间的关系是子类覆盖父类的行为。一个parent class should always be substitutable by it's children, regardless which one。如果你发现自己在问:如何确定子类型,你通常会做两件事之一“错误”:
您正在尝试根据子类型执行操作。通常,人们会选择将该动作移动到类本身,而不是类的“外部”。这也使得代码更易于管理。
您正试图通过使用继承来解决您自己介绍的问题,其中继承是不合理的。如果存在父级,并且存在子级,每个子级的使用方式不同,每个子级都有不同的方法,则只需停止使用继承。它们不是同一类型。一部电影与电视系列不一样,甚至不是很接近。当然,你可以在电视上看到两者,但相似之处就在那里停止了。
如果你遇到问题2,你可能使用继承不是因为它有意义,而只是为了减少代码重复。这本身就是一件好事,但你试图这样做的方式可能不是最佳的。如果可以的话,你可以使用合成,虽然我怀疑重复的行为会在哪里,除了一些任意的getter和setter。
那就是说,如果您的代码有效,并且您对此感到满意:那就去吧。这个答案对于如何处理OO是正确的,但我对你的应用程序的其余部分一无所知,所以答案是通用的。
答案 2 :(得分:1)
我认为第二种选择更好,使用instanceof。这通常适用于所有OOP设计,而不仅仅是PHP。
使用第一个选项,您在基类中有关于派生类的详细信息,因此必须修改您添加的每个新派生类的基类,这应该始终避免。
在添加新的派生类时保持基类不变可以促进代码重用。
答案 3 :(得分:1)
如果存在“正确”的方式,当然编码中的一切都是主观的(只要它不会对性能/可维护性产生负面影响;)),那么它就是“真理”和“布雷迪”的第二种方式已经指出了。
现在处理它们的方式(摘要中的类常量)的好处是,当你与其他开发人员合作时,它可以提供关于你如何期望抽象类与之交互的提示。
例如:
$oKillerSharkFilm = Video::factory(Video::MOVIE, 'Jaws', 'Dundundundundundun');
$oKillerSharkDocumentary = Video::factory(Video::DOCUMENTARY, 'Jaws', 'A Discovery Shark Week Special');
当然,缺点是您必须在抽象类中维护“允许的扩展名”。
您仍然可以使用问题中所示的instanceof
方法,并在摘要中维护允许的扩展名列表,主要用于控制/类型修复。