Zend_Form和Liskov替代原则

时间:2009-05-21 20:09:58

标签: oop zend-framework liskov-substitution-principle

我看到的一个非常常见的模式(我正在选择Zend Framework,只是因为我在这个问题的那一刻处理它),是这样的:

class My_Form extends Zend_Form {
     public function init() {
          $this->addElement();
     }
}

Zend_Form不是一个抽象类,但它本身是完全可用的。这似乎是“推荐”作为将你的表单“封装”成一个很好的类的地方。

这是否违反Liskov替代原则? Zend_Form的每个子类都将具有与基类不同的行为。为此使用构图会更好吗,还是我完全误解了这个原则?

2 个答案:

答案 0 :(得分:0)

  

Liskov的替换原则指出,如果程序模块使用Base类,则可以使用Derived类替换对Base类的引用,而不会影响程序模块的功能。

那么MyForm与ZendForm有何不同?它会改变程序的功能吗?

另外,请检查这2个项目符号(来自Wikipedia article):

  
      
  • 无法在子类中加强前提条件。
  •   
  • 后置条件不能在子类中被削弱。
  •   

也许你会发现MyForm与ZendForm并没有太大的不同,你可以安全地使用继承。

答案 1 :(得分:0)

Zend_Form是为继承而设计的。在使用Zend_Form时,每个人都应该记住这一点 - 实际上,Zend_Form并不是必需的,但可能是它的子类。因此,如果任何程序依赖于Zend_Form来完全像它那样运行,而不是因为它的子类可以表现 - 该程序是错误的。它不是“使用基类”,正如Liskov原则所述,它正在滥用它。

Zend_Form主要由Zend框架使用,我确信它正确使用它。

我认为对于这样的类,设计用于继承并用作基于某个框架的应用程序的构建块,“行为”的定义应该更抽象 - 将一些细节留给子类,即使类本身不是抽象的。我会说Zend_Form的行为是“渲染一些 html并使用一些验证规则”。从这个意义上讲,Zend_Form的所有子类都以相同的方式运行。由于Zend_Form非抽象只是定义了默认行为,这使得它更容易使用。

另外,为了使它更具学术性,我可以从中制作两门课程。一个应该是抽象的 - 所有形式的基类。另一个用于空表单的行为,其行为完全正确,Zend_Form现在可以自行运行。所以它会像

// sorry, I don't like PHP so here goes java 
public abstract class ZendForm{/*implementation here and NO abstract methods*/} 
public final class DefaultZendForm extends ZendForm{/*nothing here*/}

这将消除对利斯科夫原则的任何混淆,但可能不会给该计划增加任何实际价值。

子类应该是从超类的某种方式不同,否则创建子类是没有意义的。而且你总是可以滥用这种差异并编写一个适用于超类的程序,并且对子类失败。但这不合理。完全呈现默认(空)表单不是Zend_Form合同的一部分。只有属于类合同的行为才是LSP的主题。