【问题标题】:extending class but base call needs to call extended class扩展类但基调用需要调用扩展类
【发布时间】:2011-05-09 20:49:07
【问题描述】:

我有一个很大的班级,我将其分成更小的部分。

所以我有一个基类和一个扩展基类的新类。

我的问题是,我可以从基类调用扩展类吗?这似乎不对。

// a.php
class A {
    // set all the properties and runs some validation and functionality in the process
}

// b.php
class B extends A {
    // needs all the same validation as class A and adds more functionality
}

要开始这个过程我只能调用A类,例如:

$process = new A();

在 A 类中,我需要决定是否需要 B 类功能

class A {
    if($condition) {
        include_once('b.php');
        $new_process = new B();
        $new_process->doMoreStuff();
    }
}

我可以添加 doMoreStuff()(还有很多功能),但这违背了使用更小的类文件大小的目的。

如果使用 A 类或 B 类,我知道正确的方法是创建一个包装脚本并将逻辑放入其中。但是还有其他原因导致我不能按照我的要求做吗?

更新:

所以让我澄清一下 A 类是什么:

A 类设置所有数据库连接、验证 INI 属性并设置初始日志记录值。 A 类也有处理特定请求的工作流/流程。

B 类需要 A 类的数据库、INI 属性和日志记录,但也提供了新的工作流/流程。我只是想将 A 的功能扩展到另一个类(以使其更易于管理)。

所以我认为应该有一个决策类 C 决定仅使用 A 类或扩展 A 类的 B 类。

只是想确认这是最好的选择,感谢您的意见

【问题讨论】:

  • 它似乎效率不高。本质上,您现在正在加载两个 A 对象,而看起来好像只需要一个对象。如果 B 不是 A 的扩展类,那么上面的代码会更有意义。如果 A 类已经验证了数据,为什么 B 还需要包含验证?如果 B 需要来自 A 的值,A 是否可以通过方法参数将其值传递给 B?我想我们需要了解正在验证的内容才能给出一个好的答案。

标签: php class refactoring


【解决方案1】:

听起来也许您应该使用工厂模式,但如果没有更多信息很难判断。某种 oop 模式在这里适用。看看这个。

http://www.php.net/manual/en/language.oop5.patterns.php

编辑

您的想法是朝着正确方向迈出的一步,但您的应用程序似乎违反了单一责任原则 (SRP)。 A 类有几个责任,因此它可能会改变的原因有很多。您可能希望使用一个初始化类、一个处理 DB 连接的类和一个处理日志记录的类。这将使您的应用程序在将来更容易修改。然后,您可以使用依赖注入(基本上通过构造或方法参数)将这些类传递给需要它们的任何其他类,或者在需要时简单地在包装类中使用它们。

【讨论】:

  • 是的,工厂可能是他需要的东西。
  • 我确实有一个用于数据库、电子邮件、日志记录的类(都是单例),但实例是在 A 类中创建的。我认为可能是一个新的决策类,要么启动 A 类或 B 类但不是两者都
  • @Phill Pafford 很好。听起来 A 类已经是包装类。所以也许 B 类根本不应该是 A 类的扩展。相反,如果 B 类需要来自 A 类的信息,则 A 类应该通过参数将该信息传递给 B 类。
  • 这正是我想要做的,除了我需要传递给 B 类的 A 类的所有 config/args/etc.. 太大。这就是为什么我想知道我是否可以扩展 A 类。我现在正处于重写 A 类的迷雾中,所以欢迎任何设计输入
  • @Phill Pafford 也许应该将这些配置变量放入它们自己的类中。这样,您可以简单地将配置对象传递给 B 类,而不是将一百万个参数传递给 B 类。
【解决方案2】:

如果 B 类仅作为 A 类的一部分出现,那么您至少应该明确表明它不能在类外使用。在包含 b.php 之前设置一些变量或其他东西,如果它没有在 b 中设置,则错误输出,这样如果其他人包含它,则不会设置该变量,并且很明显该类不应该是在 A 类之外使用。

如果您要创建 A 的单独实例,B 真的是 A 的子类吗?初始化为 A 的新对象在构造过程中的行为类似于 B,但是如果某些方法需要 B 对象,则不能传入初始化为 A 的对象,而如果使用包装类,它实际上返回A B,对于期望 B 的地方,它可以正常工作。这取决于您的情况有多复杂,是否会出现这种情况。

【讨论】:

    【解决方案3】:

    工厂模式绝对是一种方式,但要记住的另一件事是“is a”和“has a”之间的区别。

    您现在使用继承让一切正常工作的方式是一种“是”类型的关系 b 是 a。

    有一个关系会使 b 成为它自己的类,具有 a 类型的属性。这样你就可以用一个类对象初始化 b,并利用 a 中的所有数据和验证,而这两个类没有任何基于继承的关系。

    不是对差异的最佳解释......但重要的问题是来自 a 的那些属性/方法是否实际上属于 b 上的属性或方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-22
      • 1970-01-01
      • 1970-01-01
      • 2015-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多