抽象类 - 儿童类型

时间:2012-04-23 08:40:58

标签: php oop abstract-class hierarchy children

我正在尝试设计一些类层次结构,并且我在这部分“陷入困境”。

让我们说我有以下课程

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();
}

有没有比我的解决方案更好的方法(读作:我的解决方案是否很糟糕?)?

4 个答案:

答案 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。如果你发现自己在问:如何确定子类型,你通常会做两件事之一“错误”:

  1. 您正在尝试根据子类型执行操作。通常,人们会选择将该动作移动到类本身,而不是类的“外部”。这也使得代码更易于管理。

  2. 您正试图通过使用继承来解决您自己介绍的问题,其中继承是不合理的。如果存在父级,并且存在子级,每个子级的使用方式不同,每个子级都有不同的方法,则只需停止使用继承。它们不是同一类型。一部电影与电视系列不一样,甚至不是很接近。当然,你可以在电视上看到两者,但相似之处就在那里停止了。

  3. 如果你遇到问题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方法,并在摘要中维护允许的扩展名列表,主要用于控制/类型修复。