抽象类 - 儿童类型


Abstract class - children type

>我正在尝试设计一些类层次结构,但我"卡"在这部分。

假设我有以下课程

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

在系统的不同部分,我有(解析器)类,它封装了影片和显示对象,并将对象返回给客户端。

问题:获取从解析器/工厂类返回的 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();
}

有没有比我的解决方案更好的方法(阅读为:我的解决方案很糟糕吗?

有没有比我的解决方案更好的方法(阅读为:我的解决方案很糟糕吗?

您的解决方案本身并不糟糕。但是,每当有人试图确定执行某些操作的子类型时,我都会想知道;为什么?这个答案可能有点理论,甚至可能有点迂腐,但在这里。

你不应该在乎。父类和子类之间的关系是子类覆盖父类的行为。父类应始终可由其子类替换,无论其子类是哪一个。如果你发现自己问:我如何确定亚型,你通常做两件事"错"

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

  2. 您正在尝试使用继承来解决自己引入的问题,其中继承是没有保证的。如果有父级,并且有子级,每个子项的使用方式不同,每个子项都有不同的方法,只需停止使用继承即可。它们不是同一类型。一部电影与电视系列不同,甚至没有接近。当然,你可以在电视上看到两者,但相似之处就止步于此。

如果您遇到第 2 个问题,您可能不是因为它有意义,而只是为了减少代码重复。这本身就是一件好事,但你尝试这样做的方式可能不是最佳的。如果可以的话,你可以改用组合,尽管我怀疑除了一些任意的getter和setter之外,重复的行为会在哪里。

也就是说,如果你的代码有效,并且你对它感到满意:那就去做吧。这个答案在如何处理 OO 方面是正确的,但我对您的应用程序的其余部分一无所知,所以答案是通用的。

我会选择方式 2。它抽象出您需要在Video添加另一个常量,以防您可能想要添加class SoapOpera extends Show(例如)。

使用方式#2,您不太依赖常量。无论您在不对其进行硬编码的情况下可以获得什么信息,都意味着将来在您想要扩展的情况下可能发生的问题更少。阅读有关紧固松耦合的信息。

我认为第二个选项更好,使用实例。这通常是所有OOP设计所共有的,而不仅仅是PHP。

使用第一个选项时,您有关于基类中派生类的细节,因此必须修改您添加的每个新派生类的基类,应始终避免这样做。

添加新派生类时保持基类不变可促进代码重用。

如果有一个"正确"的方法,并且编码中的一切都是主观的(只要它不会对性能/可维护性产生不利影响;)),那么这是"真相"和"布雷迪"指出的第二种方式。

按照你现在的方式做事(抽象中的类常量)的好处是,当你与其他开发人员合作时,它可以提供关于你期望如何与抽象类交互的提示。

例如:

$oKillerSharkFilm = Video::factory(Video::MOVIE, 'Jaws', 'Dundundundundundun');
$oKillerSharkDocumentary = Video::factory(Video::DOCUMENTARY, 'Jaws', 'A Discovery Shark Week Special');

当然,缺点是你必须在抽象类中维护"允许的扩展"。

您仍然可以使用问题中演示的instanceof方法,并在抽象中维护允许的扩展列表,主要用于控件/类型修复。