4

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

可以说我有以下课程

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

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

4

4 回答 4

2

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

使用方式#2,你对常量的依赖更少。无论您无需硬编码就可以获得任何信息,这意味着如果您想扩展,将来可能会发生更少的问题。阅读有关紧松耦合的信息。

于 2012-04-23T08:45:28.133 回答
2

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

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

你不应该在乎。父类和子类之间的关系是子类覆盖了父类的行为。一个父类应该总是可以被它的子类替代,不管是哪一个。如果您发现自己在问:我如何确定子类型,您通常会做两件“错误”的事情之一:

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

  2. 您正试图通过使用继承来解决您自己介绍的问题,而继承是没有保证的。如果有父类,也有子类,每一个都要不同的使用,每一个都有不同的方法,就不要再使用继承了。他们不是同一类型。电影与电视剧不一样,甚至不相近。当然,您可以在电视上看到两者,但相似之处仅止于此。

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

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

于 2012-04-23T09:10:10.030 回答
1

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

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

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

于 2012-04-23T08:49:46.637 回答
1

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

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

例如:

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

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

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

于 2012-04-23T09:06:22.300 回答