Zend_Form и принцип подстановки Лискова

Очень распространенный шаблон, который я вижу (я выбираю в Zend Framework только потому, что я имел дело с ним в момент этого вопроса), выглядит примерно так:

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

Zend_Form не является абстрактным классом, но отлично подходит для использования сам по себе. Кажется, это "рекомендуется" как место для "инкапсуляции" ваших форм в хороший класс.

Это нарушает принцип подстановки Лискова? Каждый подкласс Zend_Form будет иметь совершенно другое поведение, чем базовый класс. Было бы лучше использовать композицию для этого, или я совершенно не понимаю этот принцип?

2 ответа

Решение

Zend_Form предназначен для наследования. При использовании Zend_Form все должны помнить об этом - в действительности это не будет необходим Zend_Form, но может быть его подклассом. Таким образом, если какая-либо программа полагается, что Zend_Form будет вести себя точно так же, как и ее подкласс, - эта программа ошибочна. Это не "использование Базового класса", как утверждает принцип Лискова, это злоупотребление им.

Zend_Form используется в основном Zend Framework, и я уверен, что он использует его правильно.

Я думаю, что для таких классов, предназначенных для наследования и используемых в качестве блоков сборки приложения, основанных на некоторой структуре, определение "поведения" должно быть более абстрактным, оставляя некоторые детали подклассу, даже если сам класс не является абстрактным. Я бы сказал, что поведение для 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.

Принцип подстановки Лискова гласит, что если программный модуль использует базовый класс, то ссылка на базовый класс может быть заменена производным классом, не влияя на функциональность программного модуля.

Так чем же отличается MyForm от ZendForm? Изменит ли это функциональность программы?

Кроме того, проверьте эти 2 пули (из статьи Википедии):

  • Предпосылки не могут быть усилены в подклассе.
  • Постусловия не могут быть ослаблены в подклассе.

Возможно, вы обнаружите, что MyForm не так сильно отличается от ZendForm, и вы можете безопасно использовать наследование.

Другие вопросы по тегам