В статьерассматриваются особенности реализации и пример использования архитектурного шаблона MVCи шаблона «наблюдатель» для разработки веб-приложений на языке PHP.
Ключевыеслова: архитектурный шаблон, шаблон проектирования, MVC, наблюдатель, веб-приложение.
Современные веб-приложения должны решать множество прикладных задач, требования к ним постоянно растут, они быть надежными, эффективными, обеспечивать простоту модификации и масштабирования. Поэтому проблема разработки оптимальной архитектуры веб-приложений в настоящее время очень актуальна.
При разработке серверных веб-приложений на языке PHP все чаще применяется объектно-ориентированный подход с использованием архитектурного шаблона MVC (от англ. Model-View-Controller). Этот шаблон предполагает разделение программной системы на несколько компонентов, называемых модель (Model), вид (View) и контроллер (Controller), благодаря чему бизнес-логика приложения отделяется от пользовательского интерфейса. Такое приложение проще изменять, масштабировать, тестировать и сопровождать.
Реализовать взаимодействие между моделью и видом можно различными способами. Часто для этой цели используется поведенческий шаблон проектирования «наблюдатель» (Observer). Он позволяет классу-наблюдателю (observer) получать оповещения от класса-наблюдаемого (observable) об изменении своего состояния, реализуя тем самым схему взаимодействия «издатель-подписчик». В качестве наблюдателя в шаблоне MVC выступает вид (или несколько видов), а в качестве наблюдаемого — модель. Виды регистрируются в модели, которая оповещает их об изменении своего состояния. После получения оповещения виды извлекают из модели необходимые данные и динамически генерируют веб-страницу.
Эффективно реализовать шаблон «наблюдатель» на языке PHP можно с использованием стандартной библиотеки PHP (Standard PHP Library, SPL), которая была введена в PHP5 [1]. Для этого используются следующие классы и интерфейсы, предоставляемые SPL:
SplSubject — интерфейс, предназначенный для наследования классом-наблюдаемым. Интерфейс объявляет следующие абстрактные методы:
SplSubject::attach(SplObserver$observer) — метод, позволяющий зарегистрировать объект-наблюдатель для последующей отправки ему оповещений;
SplSubject::detach(SplObserver$observer) — метод, удаляющий наблюдателя из списка зарегистрированных;
SplSubject::notify(void) — метод, который нужно вызывать для оповещения зарегистрированных наблюдателей об изменении своего состояния.
SplObserver — интерфейс, предназначенный для наследования классом-наблюдателем. Он объявляет единственный абстрактный метод SplSubject::update(), который должен быть определен в наблюдателе. Этот метод будет вызываться, когда объект класса SplSubject вызовет метод notify().
SplObjectStorage — класс, позволяющий сохранять в контейнере и удалять из контейнера объекты классов-наблюдателей при помощи методов attach() и detach().
Рассмотрим пример PHP-приложения, построенного на основе архитектурного шаблона MVC с применением шаблона «наблюдатель» для реализации взаимодействия модели и вида.
Диаграмма UML, иллюстрирующая взаимосвязи между классами, приведена на рисунке 1.
Рис. 1. Диаграмма классов, реализующих шаблон MVC с использованием шаблона «наблюдатель»
Базовый класс Model, который будет являться родительским для всех моделей приложения, определяется следующим образом:
class Model implements SplSubject
{
private $storage;
public $status;
public function __construct($server, $user, $pass, $base)
{
$this->storage = new SplObjectStorage();
}
function attach(SplObserver $observer)
{
$this->storage->attach($observer);
}
function detach(SplObserver $observer)
{
$this->storage->detach($observer);
}
function notify()
{
foreach($this->storage as $obj)
{
$obj->update($this);
}
}
}
Классы моделей, реализующие действия, связанные с предметной областью приложения, являются потомками базового класса Model. Например, для раздела сайта, в котором можно просматривать и редактировать список подразделений организации, существуют класс Model_editPlaceInfo:
class Model_editPlaceInfo extends Model
{
//...
}
Класс View, который будет являться родительским для всех видов приложения, наследуется от класса Observer, который в свою очередь наследует интерфейс SplObserver:
abstract class Observer implements SplObserver
{
function update(SplSubject $subject)
{
$this->doUpdate($subject);
}
abstract function doUpdate(Model $model);
}
class View extends Observer
{
function doUpdate(Model $model)
{
//...
}
}
Классы видов, которые генерируют веб-страницы и передают их пользователю для отображения в браузере, являются потомками класса View. Например:
class View_editPlaceInfo extends View
{
functiondoUpdate(Model $model)
{
//...
}
}
Непосредственное создание веб-страниц производится в методе doUpdate(). Он получает указатель на объект модели, из которой он может извлечь все данные, необходимые для отображения на странице.
Запросы пользователя веб-ресурса обрабатываются с использованием шаблона Front Controller [2], который обеспечивает единую точку обработки всех входящих запросов. После анализа URL, полученного в запросе пользователя, Front Controller определяет, какой из имеющихся контроллеров MVC необходимо использовать для его выполнения, и создает объект соответствующего класса. Front Controller также определяет действие, которое контроллер должен выполнить, и вызывает соответствующий метод, например action_getPlaceInfo(). В конструкторе контроллера __construct() создаются экземпляры классов модели (Model_editPlaceInfo) и вида (View_editPlaceInfo). Далее контроллер, в соответствии с логикой работы шаблона «наблюдатель», регистрирует вид в модели путем вызова метода attach():
$model=new Model_editPlaceInfo($params["server"], $params["user"], $params["pass"], $params["base"]);
$view=new View_editPlaceInfo();
$model->attach($view);
Теперь во всех классах моделей, являющихся потомками класса Model, при каждом изменении состояния достаточно вызвать метод notify(). Все зарегистрированные виды получат оповещение, извлекут из модели необходимые данные, сгенерируют веб-страницу и передадут ее пользователю.
Изменяя реализацию классов вида, можно менять способ отображения данных для пользователя и внешнее оформление веб-страниц сайта. Изменяя классы моделей, можно менять логику работы приложения, способ хранения данных и т. д. Использование шаблона «наблюдатель» позволяет сделать модели и виды независимыми. Это значительно упрощает разработку и модификацию приложения, а также позволяет избежать множества ошибок.
Построение веб-приложения на основе объектно-ориентированного подхода с применением архитектурного шаблона MVC и поведенческого шаблона проектирования «наблюдатель» улучшает структурированность, масштабируемость и надежность программной системы, облегчает ее модификацию и сопровождение.
Литература:
1. http://www.php.net/manual/ru/book.spl.php
2. http://www.oracle.com/technetwork/java/frontcontroller-135648.html
3. Зандстра М. PHP. Объекты, шаблоны и методики программирования. М.: Вильямс, 2011.