Php 抽象类-子类类型

Php 抽象类-子类类型,php,oop,abstract-class,hierarchy,children,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 f

我试图设计一些类层次结构,但我在这一部分“卡住了”

假设我有以下几节课

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。给客户

问题:获取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();
}

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

我会选择方法2。它抽象了您需要在
Video
中添加另一个常量,以防您需要添加
类SoapOpera extensed Show
(例如)


使用方式#2,您对常量的依赖性更小。无论您不需要硬编码就可以获得什么信息,这意味着如果您想要扩展,将来可能发生的问题会更少。阅读

我认为第二个选项更好,使用instanceof。这是所有OOP设计的共同点,而不仅仅是PHP

在第一个选项中,您有关于基类中派生类的详细信息,因此必须为添加的每个新派生类修改基类,这应该始终避免

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

如果有一种“正确”的方法,并且在编码过程中一切都是主观的(只要它不会对性能/可维护性产生负面影响;),那么这就是“真理”和“布雷迪”指出的第二种方法

现在这样做(抽象中的类常量)的好处是,当您与其他开发人员一起工作时,它可以提供有关您期望如何与抽象类交互的提示

例如:

$oKillerSharkFilm = Video::factory(Video::MOVIE, 'Jaws', 'Dundundundundundun');
$oKillerSharkDocumentary = Video::factory(Video::DOCUMENTARY, 'Jaws', 'A Discovery Shark Week Special');
当然,缺点是必须在抽象类中维护“允许的扩展”

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

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

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

你不应该在意。父类和子类之间的关系是子类覆盖父类的行为。A.如果您发现自己在问:如何确定子类型,您通常会做两件“错误”的事情之一:

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

  • 您正试图通过使用继承来解决您自己介绍的问题,而继承是不被保证的。如果存在一个父级,并且存在子级,每个子级的使用方式都不同,每个子级都有不同的方法,那么就停止使用继承。他们不是同一类型的。电影和电视剧不一样,甚至不接近。当然,你可以在电视上看到两者,但相似之处就到此为止

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


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

    +1个完美的例子来解释任何问题…同意-他现在这样做的唯一好处是,如果你有不被“允许”的客户端开发人员,它允许增加一个控制级别修改抽象类-在抽象中使用常量可以让其他开发人员知道如何允许他们扩展基础。我完全同意你的观点。2.正确指出了扩展和实现之间的区别。电影和甲级联赛可能会遵循一个公共界面,允许在电视上播放,但他们可能不会共享更多内容。@Berry Langerak处理这一问题的方法是,客户通过传递某个电影的名称来请求视频,在后面我搜索/获取/解析数据,然后创建并填充右obj。根据获取的数据(可以是电影、电视节目,将来可能还会有其他类型),问题是我不在乎obj的类型。我创建,但是请求obj的客户。关心。他需要知道他可以调用什么方法……所以即使电影和电视节目不共享同一个基类,客户端仍然需要检查哪个obj。(视频类型)他得到了。也许我会把整件事都写在门面课上。不管怎么说,你让我停下来,从一开始就想一想:)@MarkoJovanovic如果对象上有那么多不同的方法,那么继承是错误的工具。您只是有两个不同的实体;)