Статьи

Управляйте сложностью с помощью шаблона фасада

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

Фасад — это шаблон дизайна, который используется практически в каждом веб-приложении, но часто не знает об этом. Термин «шаблон дизайна» создает мысленный образ чего-то сложного и сложного для понимания. Хотя иногда это может быть правдой, шаблон Facade прост в реализации. Давайте посмотрим, что такое Facade и что он делает, чтобы помочь нам написать хороший код.

Процесс заимствования книги

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

  • Пользователь заходит в библиотеку и возвращает свои заимствованные книги, чтобы она могла брать новые.
  • Пользователь должен заплатить штраф за просроченные книги.
  • Пользователь или сотрудник библиотеки ищет новую книгу.
  • Наличие книги подтверждено.
  • Если вышеуказанные шаги успешно выполнены, местоположение книги должно быть восстановлено.
  • Пользователь одалживает книгу.
  • Статус книги помечен как недоступный в системе.

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

<?php public class User { public function borrowBook() { $bookManager = new Book_Manager(); $bookManager->returnBooks(); $bookPayments = new Book_Payments(); if ($bookPayments->hasOverdueBooks()) { $bookPayments->payBookFines(); } $bookLibrary = new Book_Library(); $bookReservations = new Book_Reservations(); $book = $bookLibrary->searchBooks(); $isAvailable = $bookLibrary->isBookAvailable($book); $isReserved = $bookReservations->isBookReserved($book); if ($isAvailable && !isReserved) { $bookLibrary->locateBook($book); $bookManager->borrowBook($book); $bookLibrary->updateBookAvailability($book, $status); } } } 

Вы можете увидеть процесс заимствования книги на самом деле сложный процесс! В этой реализации пользователь должен взаимодействовать с четырьмя различными классами и примерно десятью методами для заимствования книги.

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

Реализация фасадной библиотеки

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

 <?php class Library_Facade { public function returnBooks() { // previous implementation by calling necessary classes } public function borrowBooks() { } public function searchBooks() { } public function reserveBooks() { } } 

Пользователь может заимствовать книги, вызвав метод borrowBook() класса Library_Facade как показано в следующем примере:

 <?php class User { public function borrowBook() { $libraryFacade = new Library_Facade(); $libraryFacade->borrowBook(); } } 

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

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

Определение шаблона фасада

Поскольку мы определили процесс и важность реализации шаблона Facade, теперь пришло время изучить определение шаблона. Следующее извлечено из Википедии:

Фасад — это объект, который обеспечивает упрощенный интерфейс для большей части кода, например библиотеки классов. Фасад может:

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

Вот диаграмма классов нашего примера библиотеки, которая идентифицирует компоненты, упомянутые в определении шаблона Facade.

фасад-01

Реализация в реальном мире

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

Опаут для открытой аутентификации

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

 <?php $toauth = new TwitterOAuth('consumer key', 'consumer secret'); $request_token = $toauth->getRequestToken('http://exmaple.com/twitter_oauth.php'); $_SESSION['oauth_token'] = $request_token['oauth_token']; $_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret']; if ($toauth->http_code == 200) { $url = $toauth->getAuthorizeURL($request_token['oauth_token']); header('Location: '. $url); } else { // Generate error } 

Как видите, мы вызываем набор специфичных для Twitter методов библиотеки для реализации желаемой функциональности. Подобный подход был бы необходим как для LinkedIn, так и для Facebook. Процесс уже стал сложным. Мы не разрабатываем приложение для Twitter, Facebook или Linkedin; мы должны просто проверить учетные данные и аутентифицировать пользователя. Наше приложение не должно беспокоиться о реализации каждого из этих сервисов.

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

 <?php public function login($stratergy = '') { if ($stratergy != '') { $this->opauth_lib->initialize(); } } 

Когда запрашивается ссылка для входа в систему, Opauth идентифицирует запрошенную службу по URL-адресу и инициализирует библиотеку, чтобы перенаправить пользователя для аутентификации. Теперь нашему приложению нужно только создать ссылки для входа и вызвать метод initialize. Все сложные процедуры аутентификации обрабатываются за кулисами с использованием соответствующих библиотек для каждого сервиса. Это можно считать идеальным примером для эффективного использования шаблона Фасад.

Мета-функции WordPress

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

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

  • Проверьте данные поля
  • Фильтрация данных по тегам HTML, сценариям и SQL-инъекциям.
  • Проверьте наличие поля в базе данных
  • Сохранить или обновить запись в зависимости от статуса существования

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

Теперь рассмотрим реализацию update_post_meta() для определения его функциональности как фасада:

 <?php function update_post_meta($post_id, $meta_key, $meta_value, $prev_value = '') { // make sure meta is added to the post, not a revision if ($the_post = wp_is_post_revision($post_id)) $post_id = $the_post; return update_metadata('post', $post_id, $meta_key, $meta_value, $prev_value); } function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') { // expected_slashed ($meta_key) $meta_key = stripslashes($meta_key); $passed_value = $meta_value; $meta_value = stripslashes_deep($meta_value); $meta_value = sanitize_meta($meta_key, $meta_value, $meta_type); $check = apply_filters("update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value); if (null !== $check) return (bool) $check; // Compare existing value to new value if no prev value given and the key exists only once. if (empty($prev_value)) { $old_value = get_metadata($meta_type, $object_id, $meta_key); if (count($old_value) == 1) { if ($old_value[0] === $meta_value) return false; } } $wpdb->update($table, $data, $where); } 

Показывается только необходимый код; полный исходный код функции update_metadata() доступен в файле meta.php внутри каталога wp-includes meta.php . Но вы можете видеть, что все проверки, фильтрация и обновления базы данных реализованы здесь, и только интерфейс фасада знает о деталях.

Вывод

Фасад является одним из самых простых и простых в использовании шаблонов проектирования при разработке программного обеспечения. В этой статье я говорил о различных реализациях шаблона Facade. Теперь пришло время поделиться своим опытом в комментариях ниже. Знаете ли вы какую-либо библиотеку или службу, которая использует фасады? Не стесняйтесь поделиться практической реализацией шаблона Facade, с которым вы столкнулись.

Изображение через Fotolia