У меня есть набор функций, которые я хочу переместить в класс. Они в настоящее время разделяются на несколько довольно длинных файлов. Я предпочел бы не иметь одни 2 500 файлов строки, но насколько я могу сказать, Вы не можете использовать, включают для разделения класса на несколько файлов. В теории я мог сгруппировать функции в различных классах, но они достаточно тесно связаны, что я чувствую, что они принадлежат вместе, и разделение их уменьшит часть утилиты, которую я надеюсь получить от отодвигания от процедурного подхода (с общими свойствами, а не набором параметров, которые находятся почти в каждой функции).
Я знаю, что это немного неопределенно, но какие-либо предложения/указатели? Если это имеет значение, это для прототипа, таким образом, простота управления кодом имеет приоритет по безопасности и производительности.
ОБНОВЛЕНИЕ: Позвольте мне видеть, могу ли я удалить часть неопределенности:
Этот класс/набор функций производит HTML для сложной формы. Существует много различных разделов и изменений в каждом разделе, в зависимости от приблизительно 5 или 6 параметров, которые в настоящее время передаются в функции. Я надеялся определить параметры однажды как свойства класса и затем иметь доступ к ним изо всех методов создания раздела. Если я буду использовать подклассы, то значения тех свойств не будут инициализированы правильно, следовательно требование одного класса. (Хм..., если я не определяю их как статичных. Я, возможно, просто ответил на свой собственный вопрос. Я должен буду надеяться видеть, существует ли какая-либо причина, которая не работала бы.)
Я в настоящее время получал путаницу функций как:
get_section_A ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
if ($this->type == 'foo') { }
else ($this->type == 'foo') { }
}
Таким образом, я первоначально воображал что-то как:
class MyForm {
public $type; // or maybe they'd be private or
public $mode; // I'd use getters and setters
public $read_only; // let's not get distracted by that :)
public $values_array;
// etc.
function __constructor ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
$this->type = $type;
// etc.
}
function get_sections () {
$result = $this->get_section_A();
$result .= $this->get_section_B();
$result .= $this->get_section_C();
}
function get_section_A() {
if ($this->type == 'foo') { }
else { }
}
function get_section_B() {}
function get_section_C() {}
// etc. for 2500 lines
}
Теперь я думаю что-то как:
// container class file
class MyForm {
static $type
static $mode
static $read_only
static $values_array
// etc.
function __constructor ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
MyForm::$type = $type;
// etc.
}
function get_sections () {
$result = new SectionA();
$result .= new SectionB();
$result .= new SectionC();
}
}
// section A file
class SectionA extends MyForm {
function __constructor() {
if (MyForm::$type == 'foo') { }
else { }
}
function __toString() {
// return string representation of section
}
}
// etc.
Или вероятно мне нужен абстрактный класс FormSection, где свойства живут.
Какие-либо другие идеи/подходы?
Я бы разделил их на столько классов, сколько вы хотите (или столько, которые имеют смысл), а затем определил автозагрузчик , чтобы избежать проблем с включением.
Хорошо, после просмотра большего количества вашего кода - я думаю, что вы неправильно подходите к подклассам. У вас есть много if
утверждений против $ type
, которые сигнализируют мне, что - это то, на чем должен основываться полиморфизм.
abstract class MyForm
{
protected
$mode
, $read_only
, $values
;
public function __construct( $mode, $read_only=false, array $values = array() )
{
$this->mode = $mode;
$this->read_only = (boolean)$read_only;
$this->values = $values;
}
abstract function get_section_A();
abstract function get_section_B();
abstract function get_section_C();
// final only if you don't want subclasses to override
final public function get_sections()
{
return $this->get_section_A()
. $this->get_section_B()
. $this->get_section_C()
;
}
}
class FooForm extends MyForm
{
public function get_section_A()
{
// whatever
}
public function get_section_B()
{
// whatever
}
public function get_section_C()
{
// whatever
}
}
Обычно я делаю что-то вроде этого:
class one
{
public function __get($key)
{
// require __DIR__ / $key . php
// instanciate the sub class
}
public function mainMethod()
{
}
}
class one_subOne extends one
{
public function otherMethod()
{
}
}
class one_subTwo extends one
{
public function anotherMethod()
{
}
}
$one->mainMethod();
$one->subOne->otherMethod();
$one->subTwo->anotherMethod();
Все они находятся в разных файлах, что означает, что они достаточно разные, чтобы сгруппировать их по файлам. Просто воспользуйтесь той же логикой при построении классов. У меня есть объект Page, который занимается построением страницы. Технически HTML для заголовка моей страницы является частью страницы, но я разделяю его на класс Page_HTML для поддержания моего рассудка, а не для создания гигантских классов.
Кроме того, я предпочитаю делать подклассы, такие как Page_HTML в данном случае, статическими, вместо того, чтобы создавать их экземпляры. Таким образом, я могу получить доступ к переменным $ this в классе Page, но все же сгруппировать их в другой класс.
class Page
{
function buildPage($content)
{
$content = Page_HTML::getHeader() . $content;
}
}
class Page_HTML
{
function getHeader()
{
}
}
Этот класс / набор функций выводит html для сложной формы.
Почему бы не удалить PHP из уравнения? Кажется, вы используете PHP для организации представлений, что можно легко сделать с файловой системой. Просто напишите представления в HTML, используя как можно меньше PHP. Затем используйте PHP для сопоставления запросов с представлениями. Я предполагаю, что вы обрабатываете формы с помощью PHP и можете продолжать это делать. Однако ваши классы станут намного меньше, потому что они только принимают, проверяют и предположительно сохраняют ввод.
Что касается построения представления, вы можете попробовать шаблон CompositeView .
Вот небольшой пример того, как это может выглядеть в PHP. Для этого примера представьте, что View :: $ html
инкапсулирован в класс Template, который может загружать html с диска и позволяет вводить переменные, обрабатывать экранирование вывода и т. Д.
interface IView {
public function display();
}
class View implements IView {
public $html = '';
public function display() {
echo $this->html;
}
}
class CompositeView implements IView {
private $views;
public function addPartial(IView $view) {
$this->views[] = $view;
}
public function display() {
foreach ($this->views as $view) {
$view->display();
}
}
}
Причина, по которой интерфейс IView состоит в том, чтобы позволить вам создавать составные представления с другими составными представлениями.
Итак, теперь рассмотрим форму, состоящую из трех частей: заголовок, тело и нижний колонтитул.
class HeaderView extends View {
public function __construct() {
$this->html .= "<h1>Hi</h1>\n";
}
}
class BodyView extends View {
public function __construct() {
$this->html .= "<p>Hi there.</p>\n";
}
}
class FooterView extends View {
public function __construct() {
$this->html .= "<h3>© 2012</h3>\n";
}
}
(Опять же, вы не будете просто писать HTML в эта общедоступная переменная и обработать вывод, экранируясь самостоятельно. Скорее всего, вы укажете имя файла шаблона и зарегистрируете свои данные через интерфейс шаблона.)
Затем, чтобы собрать все вместе, вы должны:
$view = new CompositeView();
// here you would make decisions about which pieces to include, based
// on your business logic. see note below.
$view->addPartial(new HeaderView());
$view->addPartial(new BodyView());
$view->addPartial(new FooterView());
$view->display();
Итак, теперь ваши представления могут быть составлены, а фрагменты повторно использованы, но вы можете легко испортить код, который их строит, особенно если у вас много условий и много различных возможных результатов (что, похоже, так и есть. ) В этом случае шаблон Стратегия, вероятно, поможет.
Если вы еще не читали статью Дядя Боба о SOLID , сделайте это прежде всего! По крайней мере, принцип единой ответственности. Я также порекомендовал бы когда-нибудь прочитать книгу Джошуа Кериевского «Рефакторинг под шаблоны».
Если вы еще не читали статью Дядюшки Боба о SOLID , сделайте это прежде всего! По крайней мере, принцип единой ответственности. Я также порекомендовал бы когда-нибудь прочитать книгу Джошуа Кериевского «Рефакторинг под шаблоны».
Если вы еще не читали статью Дядюшки Боба о SOLID , сделайте это прежде всего! По крайней мере, принцип единой ответственности. Я также порекомендовал бы когда-нибудь прочитать книгу Джошуа Кериевского «Рефакторинг под шаблоны».
Если вы хотите сделать операцию ООП, разделите проблемы и инкапсулируйте их в соответствующие классы. Комбинируйте их либо по расширению, либо по составу, либо по лучшей группировке. Удалите любой дублирующий код. Не повторяйтесь.
В вашем случае, отделите вещи, относящиеся к любой форме, от вещей, относящихся к вашей конкретной форме. Код, который может быть использован для любой формы - это код, который вы хотите поместить в общий класс формы. Вы можете повторно использовать его в более поздних проектах. Для примера очень сложного класса формы посмотрите Zend_Form.
Все в вашем коде, что связано со специфической формой, попадает в собственный класс, который расширяет общую форму. Предположив, что из свойства type
, данного в вашем коде, вы можете получить несколько классов специальной формы (вместо одного типа-fits-all-form), что, скорее всего, устранит сложность методов getSection
и сделает ваш код намного проще в обслуживании, потому что вы можете сконцентрироваться на том, как должен выглядеть и что должен делать конкретный тип формы.
Наконец, если у вас есть код, который получает данные для формы изнутри формы или иным образом не имеет прямого отношения к построению формы, удалите его и сделайте из него отдельный класс. Помните, что вы хотите отделить заботы и ваши классы формы заботятся о том, чтобы построить форму, а не получать ее данные или что-то в этом роде. Данные - это то, что вы захотите передать форме через конструктор или специальный сеттер
.