// codeart.ru / Главная / Функции или классы - мысли в слух Форум

Функции или классы - мысли в слух rss подписка

Автор: Evgeny Sergeev

Раньше я думал, что программирую плохо, потому-что мне не хватает знаний о теории программирования. Теперь, когда в башке сидит куча теоретической информации - типа “принцип открытия закрытия“, “правило подстановки Барбары Лискоу“, “принцип инверсии зависимостей” и т.д. Я понимаю, что программирую плохо, потому-что слишком много думаю о том, что пишу. Но продолжая испытывать неудовлетворенность от написанного кода, я пытаюсь найти пути его улучшения. Сегодня задумался о том, почему на каждый “чих” нужно писать класс, чем функции хуже?

Почему класс, а не функция?

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

Допустим у меня есть задача - объединить содержимое всех текстовых файлов из одной директории. Решить данную задачу можно одной функцией, что-то типа:


function concat($dir) {
//... здесь обходим директорию и возвращаем содержимое всех найденных файлов.
}

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

Например, ситуация: хочется объединить все javascript файлы в один, для того, чтобы клиент (браузер) мог получать все скопом, а не по отдельности. На Кохане (Kohana) это может быть следующий action:

class Controller_Loader extends Controller {

        public function action_all_javascript()
        {
                echo concat(‘./js/’);
        }
}

И опять не вижу в этом, ничего плохого! Кроме одного “но” - как правило, нужно загружать файлы не в произвольном порядке, а во вполне определенном. Для этого проставляю в начале каждого файла номер, соответствующий порядку его загрузки, например: “1core.js“, “2app.js” и т.д. Для того, чтобы не менять контроллер правлю функцию таким образом, чтобы она перед объединением файлов отсортировала их в нужном порядке.

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

А что если сделать несколько функций?

Раз новые требования вызывают сложности, то почему не сделать несколько функций вместо одной? Ведь до сих пор не понятно нужен ли класс в данной ситуации!

Ввожу дополнительное требование - порядок объединения файлов касается не только файлов, но и директорий, т.е. необходимо объединить файлы в текущей директорий, затем найти поддиректорию у которой наименьший порядковый номер и объединить файлы в ней и так рекурсивно обойти все дерево. Логика сложна даже для описания, а для реализации подавно.

Одной функцией здесь уже не обойтись, поэтому делаю блюдо из трех функций:

class Controller_Loader extends Controller {

        public function action_all_javascript()
        {
                $fileList = scan_tree(‘./js/’);
                $sortedFileList  = sort_files_tree($filesList);
                echo concat($sortredFileList);
        }
}

Преимущества:
Во-первых, в параметрах функций используются простые типы - строка и массив, а это значит что функции получились абсолютно не связанными;
Во-вторых, можно вводить новые сортировки и изменять порядок сканирования, используя указатели на функции.

Недостатки:
Во-первых, появился некий контекст - список файлов и содержимое фалов (явный намек на создание класса);
Во-вторых, логика функции sort_files_tree - невероятно сложная, а значит ее придется разбивать на отдельные подзадачи, что равносильно созданию дополнительных функций (уже появляется некоторая связанность);
В-третьих, добавление новых требований (например: обработка ошибок, объединение файлов определенного типа, разный порядок сортировки и т.д.) приведет к увеличению количества функций и, в конечном итоге, к дублированию кода;

Вывод

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

Вывод из всего сказанного простой - функции не плохое решения для простых задач, для сложных предпочтительнее строить классы. Остается определить какие задачи простые, а какие сложные.

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

  1. Спасибо, вот теперь кое-что начало проясняться. Блин - в любой книжке по сабжу есть описание класса, а вот в каких случаях он необходим (именно необходим, а не “можно использовать”) - описано, как правило, довольно невнятно

  2. Последний абзац самый главный :)

Leave a Reply

« Как подключить Bazaar к CruiseControll Существует ли реальная выгода от шаблона fake it в tdd? »