Конструктор подкласса с другим количеством параметров - PullRequest
5 голосов
/ 09 мая 2011

В моем приложении есть несколько элементов, которые отображаются по-разному. Я создал абстрактный класс, в котором они расширяются.

abstract class Element {

    protected $_value = null;

    public function __construct($value) {
        $this->_value = $value;
    }

    // ...

    public abstract function render();

}

Примером элемента может быть текст, заключенный в тег абзаца.

class TextElement extends Element {

    public function render() {
        return "<p>{$this->_value}</p>\n";
    }

}

У меня проблемы с созданием элементов с более чем одним значением. Например, элемент изображения может отображать тег изображения и включать несколько атрибутов. Это проблема, поскольку конструктор в абстрактном классе принимает только один параметр. Я вижу два возможных решения этой проблемы. Я мог бы передать массив, содержащий различные атрибуты, конструктору Element (решение 1) или переопределить конструктор в подклассе (решение 2). Мой вопрос в том, какое из этих решений является лучшим дизайном или существует лучшее решение? Должен ли я использовать интерфейс вместо этого?

Раствор 1

class ImageElement extends Element {

    public function render() {
        return "<img src=\"{$this->_value['src']}\" alt=\"{$this->_value['alt']}\" />";
    }

}

$imageElement = new ImageElement(array('src' => '/image.png', 'alt' => 'image'));

Решение 2

class ImageElement extends Element {

    protected $_alt;

    public function __construct($src, $alt) {
        $this->_value = $src;
        $this->_alt = $alt;
    }

    // ...

    public function render() {
        return "<img src=\"{$this->_value}\" alt=\"{$this->_alt}\" />";
    }

}

Ответы [ 3 ]

1 голос
/ 09 мая 2011

Оба решения верны, но в вашем случае я бы выбрал ваше первое решение.Здесь вы имеете дело с элементами HTML, поэтому это, вероятно, означает, что вы собираетесь поддерживать большое количество атрибутов, многие из которых являются необязательными.Это выглядит хорошо:

class ImageElement extends Element {
    public function __construct($src, alt) {...}
}

$img = new ImageElement('/img/src.png', 'alt text');

Это не так приятно

class ImageElement extends Element {
    public function __construct($src, $alt, $id = null, $class = null, $width = null, $height = null, $style = null, $title = null) {...}
}

$img = new ImageElement('/img/src.png', 'alt text', null, 'img-class', null, null, null, 'Image title');

Когда вам нужно передать несколько аргументов, многие из которых необязательны, лучше передать объект или массивконструктор.Это выглядит намного лучше:

$img = new ImageElement(array(
    'src' => '/img/src.png',
    'alt' => 'alt text',
    'class' => 'img-class',
    'title' => 'Image title',
));
1 голос
/ 09 мая 2011

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

Со вторым решением, если ваша IDE поддерживает автозаполнение или если вы сгенерировали документацию из источника, вам будет предоставлен список аргументов и вы сможете быстрее провести свой день.

$ value на самом деле не говорит мне много о том, для чего он используется и что, если вы столкнетесь с элементом, который не имеет ЛЮБЫХ параметров? то есть элемент BR или что-то.

Я думаю, что решение 2 более «правильное», но интерфейс, в котором нет ничего, кроме функции «рендеринга», является лучшим решением.

0 голосов
/ 09 мая 2011

Перегрузка!к сожалению, PHP не выполняет перегрузку, поэтому сделайте вид:

public function __construct($VAL){
    if(is_array($VAL)){
        foreach($VAL as $k=>$v){
            $this->$k=$v;
        }
    }else{
        $this->_value=$VAL;
    }
}
...