Полиморфизм с некооперативной иерархией классов - PullRequest
1 голос
/ 02 марта 2010

У меня есть сценарий, в котором у меня есть несколько классов, которые происходят от общего предка, потому что все они имеют общие свойства и методы. Половина этих классов (группа A) содержит свойство, которое не используется другой половиной (группа B), поэтому каждый класс в группе A явно объявляет это свойство, а не родительский класс.

например.

class parent
{

}

class child1 <and child2, and child3> extends parent
{
    protected $specialProperty;
}

class child4 <and child5, and child5> extends parent
{
    // no "$specialProperty"
}

У меня есть некоторое поведение, которое мне нужно реализовать, которое действует на $specialProperty. Естественно, я хотел бы поместить это в родительский класс и сделать это только один раз, но $specialProperty существует не во всех дочерних классах.

Один из вариантов - создать промежуточный абстрактный класс, который объявляет $specialProperty и реализует требуемое поведение, но я не хочу этого делать по нескольким причинам:

  1. Этот сценарий будет развиваться более скоро. Что мне тогда делать? Создать 5 или 6 различных промежуточных абстрактных классов для каждой из этих функций?
  2. Иерархия классов уже на 5 уровней выше parent. Должен ли я действительно создавать все больше и больше слоев, чтобы компенсировать неидеальную иерархию классов, которая была спешно разработана с ограниченными требованиями?
  3. По крайней мере, что касается PHP, не приведет ли так много уровней наследования к проблемам с производительностью?

Другой вариант заключается в следующем:

class parent
{
    public function functionThatTheAppWillCallAutomatically()
    {
       if ( property_exists($this, 'specialProperty') )
       {
           // do stuff with specialProperty
       }
    }
}

"вещи" будут выполняться дочерними классами, которые имеют $specialProperty и пропускаются теми, кто этого не делает. Я ненавижу это решение, хотя, потому что оно мне просто кажется неправильным и небрежным. По моему мнению, родитель не должен решать, что делать, основываясь на свойствах ребенка (черт возьми, он, вероятно, даже не должен знать, что ребенок существует - разве это не причина для дочернего класса в первую очередь ?)

Короче говоря, я не уверен, какой из этих двух вариантов наименее плох, или есть ли лучшая возможность. Я с нетерпением жду предложений.

Спасибо!


EDIT:

Я сделал следующее, чтобы реализовать эту специализированную функциональность.

class archivalDecorator extends decoratorBase /* decoratorBase just has constructor and the object property */
{
    public function archive()
    {
        if ( !$this->object->archive() )
        {
            return false;
        }

        if ( property_exists($this->object, 'specialProperty') )
        {
            // do extra stuff here that involves "specialProperty"
        }

        return true;
    }
}

Таким образом, все мои объекты выполняют один и тот же рабочий процесс архивирования, но классы, которые требуют особого поведения, могут выполнять его, и мне не нужно реализовывать десятки подклассов в иерархии для этих особых случаев.

Хотя я все еще использую property_exists(...), чтобы определить, нужно ли специальное поведение или нет, я думаю, что сейчас все в порядке, потому что я не делаю это из родительского класса. $specialProperty является публичным свойством, поэтому нет никаких причин, по которым внешние классы не должны знать об этом, но что-то не так в родительском классе, проверяющем это свойство в дочернем классе с помощью $this.

Надеюсь, я не неправильно применил эту концепцию.

Ответы [ 3 ]

1 голос
/ 02 марта 2010

Я не слишком знаком с PHP, и нет никакой специфики иерархии классов, но я хочу прокомментировать ваши опасения по поводу глубины иерархии классов.

Если то, что вы моделируете, достаточно неоднородно с точки зрения его свойств, что вы в конечном итоге получаете глубокую иерархию классов, то нет смысла ставить искусственный предел и говорить: «пять уровней в порядке, но не шесть», или «x много посредников слишком много ". Если вы не можете абстрагировать определенные различия и не представлять их вообще, помещая несколько экземпляров в одни и те же «классы эквивалентности», вам придется где-то моделировать разбиение, и это может быть так же хорошо, как и любое другое. Если вы не сделаете это в иерархии типов, вы можете получить проверку типов или дополнительные свойства.

Если вы обнаружите, что у вас слишком сложная иерархия, поскольку наличие определенных свойств перекрывается, вы можете захотеть взглянуть на множественное наследование (или реализацию с несколькими интерфейсами), например, на шаблон декоратора, если это удобно поддерживать в PHP.

1 голос
/ 02 марта 2010

Трудно сказать, не зная, что делают ваши классы, но ваши проблемы (глубокие иерархии классов с несколькими поддеревьями, дополнительная функциональность кросс-дерева и т. Д.) Свидетельствуют о необходимости какого-то шаблона декоратора .

0 голосов
/ 02 марта 2010

Хорошо, у вас есть специальное свойство, которое существует только в каком-то классе, и у вас есть метод, который должен воздействовать на это специальное свойство, но вы не знаете, где его разместить?
А в каком классе вы определяете специальное свойство?

class child1 <and child2, and child3> extends parent
{
    protected $specialProperty;

    public function doSomethingWithSpecialProperty() {

   }
}

Другой вариант - переопределить метод родителя:

class child1 <and child2, and child3> extends parent
{
    protected $specialProperty;

    public function functionThatTheAppWillCallAutomatically() {
        parent::functionThatTheAppWillCallAutomatically();
        // do other stuff
    }
}

Вы также можете создать пустой метод, который действует как заполнитель, и при необходимости внедрить его в дочерние классы:

class parent
{
    public function functionThatTheAppWillCallAutomatically()
    {
       $this->extraStuff();
    }
    protected function extraStuff(){};
}


 class child1 <and child2, and child3> extends parent
 {
    protected $specialProperty;

    protected function extraStuff() {
        echo $specialProperty,
    }
 }

В противном случае вам, возможно, придется снова подумать о своем дизайне.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...