PHP Design Patterns: плохие частные конструкторы для классов, которые вы позволите другим расширять? - PullRequest
4 голосов
/ 09 декабря 2011

У меня есть абстрактный класс с именем ContentAbstract, который выглядит примерно так

abstract class ContentAbstract
{
  protected static $type;
  protected $id;
  protected $title;
  protected $description;

  protected $page;
  protected $section;
  ...

  function __construct($id = NULL, Page $page = NULL, Section $section = NULL)
  {
    if($id != NULL)
    {
      $data = get_data_from_content_table_by_id($id);

      if($data['type'] == static::$type)
      {
        initialize_fields_with_data($data);

        $this->page = fetch_page_object_from_registry($data['page_id']);
        $this->section = fetch_section_object_from_registry($data['section_id']);
      }
      else
        throw new IncompatibleContentTypeException('Foo');
    }
    else if($page != NULL && $section != NULL)
    {
      $this->page = $page;
      $this->section = $section;
    }
    else
      throw new OphanContentException('Foo');
  }
}

Тогда класс Page также является подклассом ContentAbstract

class Page extends ContentAbstract
{
  protected static $type = 'Page';

  private $template_file;
  private $short_name;

  static function newFromName($name)
  {
    $data = get_content_id_from_page_table_using_the_short_name($name);
    $page = new Page($data['id']);
    $page->template_file = $data['template_file'];
    ...
  }

  static function newFromID($id)
  {
    $data = get_content_id_from_page_table_using_the_ID($id);
    $page = new Page($data['id']);
    $page->template_file = $data['template_file'];
    ...
  }
}

ТеперьМоя проблема заключается в том, что конструктор Page является общедоступным, и пользователи могут сделать это:

$page = new Page($valid_page_id);

и в итоге вызовут ContentAbstract::__construct(), но не смогут инициализировать данные для самой страницы (template_file и short_name), поскольку он был вызван вне Page::newFromName() и Page::newFromID().Таким образом, я получаю полуготовые данные содержания .Одним из решений было бы переопределить родительский конструктор чем-то похожим на Page::newFromID(), убедившись, что мы сможем установить все поля при создании экземпляра Page (конечно, все еще вызывая родительский конструктор в Page::__construct()).

Теперь проблема заключается в методе Page::newFromName(), так как такой подход потребует от меня сделать 2 запроса, один из них - получить идентификатор содержимого страницы, используя столбец short_name, а затем, когда конструкторстраница вызывается в Page::newFromName(), затем она создает новый запрос для получения данных, связанных со страницей.Это не желательно, не так ли?

Так что единственное решение, которое я вижу, - это сделать Page::__construct() частным и заставить конечных пользователей использовать статические методы для создания экземпляра объекта.

Мой вопросЭто то, что я хотел бы выпустить как проект с открытым исходным кодом, и это позволяет пользователям добавлять больше типов содержимого, просто создав подкласс класса ContentAbstract.Требует ли частный конструктор вреда для указанной цели (учет человеческих ошибок и лени для чтения документации)?Или такие вопросы должны быть наименьшей из моих забот?Или структуры реальных классов сами по себе способствуют этой проблеме?

1 Ответ

0 голосов
/ 09 декабря 2011

"Теперь моя проблема заключается в том, что конструктор Page является общедоступным, и пользователи могут сделать это:

$ page = new Page ($ valid_page_id);"

Согласно кодуВы отправили в OP, это не должно иметь место.Ваша страница расширяет ContentAbstract, где находится конструкция, но вы на самом деле не вызываете конструкцию из класса Page.Вы должны были бы принудительно позвонить родителю от ребенка:

class Page extends Content // I wouldn't name this abstract as it may change in the future
{
    public function __construct($args)
    {
        // Here I forced a call to parent
        // If I comment this out, the parent construct will never be accessed
        parent::__construct($args); 
    }
}
...