PHP и объекты - расширение общего объекта, от которого наследуются другие объекты - PullRequest
0 голосов
/ 18 августа 2011

У меня есть базовый объект (form_field_base), который расширен / унаследован другими объектами в виде:

class form_field_base {
    // Lots of code
}
class form_field_text extends form_field_base {
    // Lots of code
}
class form_field_email extends form_field_text {
    // Extending the text object to update validation, and set input type="email"
}
class form_field_file extends form_field_base {
    // Lots of code, for example uploading files
}

«form_field_base» предоставляет вспомогательные методы, которые используются всеми типами полей формы, например, функция html () вызывает конкретный объект (form_field_email :: html_input) для получения поля, а затем помещает его в строку со стандартным тег и т. д.

Все эти объекты используются во многих проектах.

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

Так как это должно быть организовано?

В идеале у меня не будет полной копии "form_field_base", так как это приведет к дублированию кода.

И кажется, что наличие фиктивных промежуточных объектов довольно трудоемко:

class form_field_base_common {
    // Lots of code
}
class form_field_base extends form_field_base_common {
    // By default is empty
}

class form_field_text_common extends form_field_base {
    // Lots of code
}
class form_field_text extends form_field_text_common {
    // ...
}

class form_field_email_common extends form_field_text {
    // Extending the text object to update validation, and set input type="email"
}
class form_field_email extends form_field_email_common {
    // ...
}

class form_field_file_common extends form_field_base {
    // Lots of code, for example uploading files
}
class form_field_file extends form_field_file_common {
    // ...
}

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

Неужели должен быть лучший способ?

Ответы [ 3 ]

1 голос
/ 18 августа 2011

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

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

Ваша ситуация для всех существующих проектов:

A <- B <- C

A->a()
B->a(), B->b()
C->a(), C->b(), C->c()

Ваш новый проект (скажем, проект 1) должен иметь:

A1 <- B <- C

A1->a(), A1->a1(),
B->a(), B->a1(), B->b()
C->a(), C->a1(), C->b(), C->c()

Шаблон декоратора требует, чтобы вы создали декоратор для каждого объекта, который вы хотите расширить (A1, B1, C1). Вы хотите, чтобы пользовательские методы A1 также были доступны в ваших декорациях B1 и C1, поэтому вам нужно связать их так же, как и исходные классы.

A1 decorates A
B1 decorates B
C1 decorates C

A1 <- B1 <- C1

A1->a1()
B1->a1()
C1->a1()

Вы по-прежнему хотите, чтобы функциональность A, B, C также присутствовала в ваших классах декорирования, поэтому вам нужно создать связь между каждым декоратором и его исходным классом декорирования и делегировать соответствующие методы:

A1 hosts a reference of A
B1 hosts a reference of B
C1 hosts a reference of C

A1->a() ----> $this->myA->a();
B1->a() ----> $this->myB->a();
B1->b() ----> $this->myB->b();

Все пользовательские методы проекта 1 выполняются напрямую:

A1->a1() ----> $this->a1();

В вашем новом проекте 1 вы используете:

A1 instead of A
B1 instead of B
C1 instead of C

Вашим A1, B1 и C1 может быть разрешено создавать свои экземпляры A, B, C прямо в их конструкторе, хотя вы можете пропустить эти экземпляры, чтобы включить несколько декораций. В этом случае вам понадобятся надлежащие интерфейсы, скажем, IA, IB, IC. Тогда у вашего A1 может быть метод setA(IA theA), где theA может быть точным A или даже A1, A2 или A3 ... Но это более продвинутое, и вы найдете больше информации, погуглив образец декоратора, и вам, возможно, понадобится немного немного опыта работы с интерфейсами и полиморфизмом.


Итого:

  1. Оставьте вашу цепочку наследования такой, какая она есть

  2. Создание цепочки декораторов для каждого индивидуального проекта

  3. Свяжите декораторы с их исходным классом и делегируйте общие функции.

  4. Используйте декораторы вместо оригинальных классов в вашем пользовательском проекте. Теперь они идентичны своим оригиналам и имеют дополнительные методы, которые вы хотите добавить.

0 голосов
/ 18 августа 2011

Если у вас уже есть хороший базовый класс для всех полей формы, который работает без текста справки, оставьте его как есть.Вместо этого создайте класс, который будет представлять компонент формы.Это может быть более высокий уровень абстракции:

abstract class FormComponent {
    public __construct(FormField $field) {
        $this->_field = $field;
    }

    public html() {
        // Here you can choose any way to integrate the field's input HTML into
        // the component's HTML. You can wrap it in a label, for example.
        return $self->_get_html() . $self->_field->html_input();
    }
}

ОБНОВЛЕНИЕ: вам не нужно трогать цепочку наследования form_field, вы можете оставить все как есть.Если вы сделаете это таким образом, вам нужно будет внедрить ваши экземпляры полевых объектов в класс компонента следующим образом:

$field = new form_field_email($arguments); // Whatever arguments it takes

// Here the FormComponent_Email class inherits the FormComponent class
$component = new FormComponent_Email($field);
$component->set_hint('Some hint'); // Set your help text here
$component->set_label('Enter your email');

// You can even add an error container if you wish
if ($some_email_error) {
    $component->set_error('Your email has an error!');
}

$component_html = $component->html();

Здесь, внутри метода html класса компонента электронной почты, вы можете добавить перенос HTML вполе, в котором будут отображаться метка, контейнер подсказок, контейнер ошибок и все остальное, что вам нужно.

0 голосов
/ 18 августа 2011

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

1 - Создайте текстовый объект справки для ваших целей. 2 - Создайте необязательный параметр конструктора в вашем классе form_field_base. Если установлено, это будет частный экземпляр класса справки. 3 - Внутри ваших подклассов проверьте наличие текстового объекта справки. Если он установлен, выполните дополнительное действие.

Возможно, это не подходит для того, что вы пытаетесь сделать, хотя. Но, не будучи более уверенным, это лучшее, что я могу придумать!

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