Домой / Скайп / Паттерны проектирования фасад. Remote Facade (Парадный вход). Описание Remote Facade

Паттерны проектирования фасад. Remote Facade (Парадный вход). Описание Remote Facade

Описание Remote Facade

Предоставляет общий объединяющий интерфейс для набора методов объекта для улучшения эффективности сетевого взаимодействия.

Паттерн Remote Facade в объектно-ориентированной модели улучшает работу с маленькими объектами, у которых маленькие методы. Маленькие методы открывают большие возможности для контроля и изменения поведения, а также для улучшения понимания клиентом работы приложения. Одно из последствий такого "мелко-молотого" поведения в том, что обычно происходит много взаимодействий между объектами с вызовом множества методов.

В одном адресном пространстве "мелко-молотые" взаимодействия работаю хорошо, но всё меняется, когда происходит взаимодействие между процессами. Удалённые вызовы более затратны, потому что многое надо сделать: иногда данные нужно упорядочить, проверить на безопасность, пакеты должны быть маршрутизированы на свичах. Если два процесса работают на разных краях света, даже скорость света может играть роль. Тяжелая правда в том, что любые межпроцессные взаимодействия на порядок более расточительны, чем анутрипроцессные вызовы. Даже, если оба процесса работают на одной машине. Такое влияние на производительность не может быть упущено из вида, даже приверженцами ленивой оптимизации.

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

Паттерн Remote Facade представляет собой общий "Фасад" (по GoF) поверх структуры более "мелко-молотых" объектов. Ни один из этих объектов не имеет удалённого интерфейса, а Remote Facade не включает в себя никакой бизнес-логики. Всё, что делает Remote Facade - это транслирует общие запросы в набор небольших запросов к подчинённым объектам.

Почитать описание других паттернов.

Проблема

Минимизировать зависимость подсистем некоторой сложной системы и обмен информацией между ними.

Описание

При проектировании сложных систем, зачастую применяется т.н. принцип декомпозиции, при котором сложная система разбивается на более мелкие и простые подсистемы. Причем, уровень декомпозиции (ее глубину) определяет исключительно проектировщик. Благодаря такому подходу, отдельные компоненты системы могу быть разработаны изолированно, затем интегрированы вместе. Однако возникает, очевидная на первый взгляд, проблема - высокая связность модулей системы. Это проявляется, в первую очередь, в большом объеме информации, которой модули обмениваются друг с другом. К тому же, для подобной коммуникации одни модули должны обладать достаточной информацией о природе других модулей.

Таким образом, минимизация зависимости подсистем, а также снижение объема передаваемой между ними информации - одна из основных задач проектирования.

Один из способов решения данной задачи - использование паттерна «Фасад».

Паттерн «Фасад» предоставляет унифицированный интерфейс вместо набора интерфейсов некоторой подсистемы. Фасад определяет интерфейс более высокого уровня, кото-
рый упрощает использование подсистемы.

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

Практическая задача

Используя паттерн «Фасад», реализуем унифицированный интерфейс к некоторой подсистеме авторизации пользователей. Сама подсистема авторизации (в данном примере), безусловно не претендует на «сложную систему», однако она отчетливо отображает основные достоинства паттерна.

Диаграмма классов

Рассмотрим диаграмму. Каркас подсистемы авторизации, для наглядности, выделен в прямоугольник. Фасад Authorizator предоставляет клиенту унифицированный интерфейс для работы с подсистемой. В данном случае, это всего один метод - authorizate(), однако их могло быть и больше. При этом, клиент может использовать фасад для работы с подсистемой, а может, непосредственно пользоваться классами, составляющими ее. Сам процесс авторизации достаточно прост. На основании имени пользователя ищется соответствующая запись в базе данных, посредством интерфейса DB. Затем, сравнивается пароль найденной записи с паролем указанным пользователем.

Реализация на С#

В коде реализации нет класса PgSQLDB.
using System;
using System.Collections.Generic ;
using System.Linq;
using System.Text;
using System.Security;

namespace Facade
{
//Абстрактный класс пользователя
abstract class User
{
protected string username;
protected string passwd;

public abstract string getUserRole();

public string getPasswdHash()
{
// Это строка не несет какой-либой смысловой нагрузки.
// Безусловно, таким образом мы получаем небезопасный хеш-код пароля
return passwd.GetHashCode().ToString();
}
}

// Уточнение пользователя, в качестве пользователя по-умолчанию
class DefaultUser: User
{
public DefaultUser(string username, string passwd)
{
this .username = username;
this .passwd = passwd;
}


{
return "DEFAULT_USER" ;
}
}

// Уточнение пользователя, в качестве администратора
class Administrator: User
{
public Administrator(string username, string passwd)
{
this .username = username;
this .passwd = passwd;
}

public override string getUserRole()
{
return "ADMINISTRATOR" ;
}

// Интерфейс доступа к базе данных
interface DB
{
User search(string username);
}

// Реализация интерфейса БД для SQLite
class SQLiteDB: DB
{
public SQLiteDB(string filename)
{
// Инициализация драйвера БД
}

public User search(string username)
{
// Заглушка
throw new NotImplementedException();
}
}

// Авторизация пользователя
public void authorizate(string username, string passwd)
{
DB db = new SQLiteDB("db.sqlite" );
User user = db.search(username);
if (user.getPasswdHash() == passwd)
{
// все хорошо, пользователь опознан
}
else
{
// что-то пошло не так
throw new SecurityException("Wrong password or username!" );
}
}
}

class Program
{
static void Main(string args)
{
// Вымышленный пользователь
string username = "Vasya" ;
string passwd = "qwerty" .GetHashCode().ToString();

Authorizator auth = new Authorizator();
try
{
auth.authorizate(username, passwd);
}
catch (SecurityException ex)
{
// Пользователь не прошел аутентификацию
}
}
}
}


* This source code was highlighted with Source Code Highlighter .

PS : У меня у одного хабраредактор не работает?

Фасад (Facade ) — это поведенческий шаблон проектирования. Данный шаблон позволяет скрыть сложность системы путём сведения всех возможных вызовов к одному объекту, делегирующему их соответствующих объектам системы.

Простейшая схема работы паттерна:

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

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

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

Шаблон проектирования «фасад» занимается именно такими случаями. Он позволяет спрятать всю сложность процесса за простым интерфейсом.

Создадим классы для работы привода микроволновки (вращения), мощности и оповещения.

В классе привода, будет всего 2 действия: поворот направо и поворот налево.

Class Drive { public void TurlLeft() { Console.WriteLine("Повернуть влево"); } public void TurlRight() { Console.WriteLine("Повернуть вправо"); } }

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

Class Power { private int _power; public int MicrowavePower { get { return _power; } set { _power = value; Console.WriteLine("Задана мощность {0}w ", _power); } } }

В классе оповещения добавлены методы для оповещения о начале и завершении работы.

Class Notification { public void StopNotification() { Console.WriteLine("Пик-пик-пик - операция завершена"); } public void StartNotification() { Console.WriteLine("Пик - начат процесс готовки"); } }

Осталось реализовать сам класс микроволновой печи. В данном примере он же будет являться фасадом. В классе реализуем методы для разморозки и разогрева продуктов.

Class Microwave { private Drive _drive; private Power _power; private Notification _notification; public Microwave(Drive drive, Power power, Notification notification) { _drive = drive; _power = power; _notification = notification; } public void Defrost() { _notification.StartNotification(); _power.MicrowavePower = 1000; _drive.TurlRight(); _drive.TurlRight(); _power.MicrowavePower = 500; _drive.TurlLeft(); _drive.TurlLeft(); _power.MicrowavePower = 200; _drive.TurlRight(); _drive.TurlRight(); _power.MicrowavePower = 0; _notification.StopNotification(); } public void Heating() { _notification.StartNotification(); _power.MicrowavePower = 350; _drive.TurlRight(); _drive.TurlRight(); _drive.TurlRight(); _drive.TurlRight(); _drive.TurlRight(); _drive.TurlLeft(); _drive.TurlLeft(); _drive.TurlRight(); _drive.TurlRight(); _drive.TurlLeft(); _drive.TurlLeft(); _drive.TurlLeft(); _drive.TurlLeft(); _power.MicrowavePower = 0; _notification.StopNotification(); } }

Вот и всё, пример готов, осталось протестировать.

Var drive = new Drive(); var power = new Power(); var notification = new Notification(); var microwave = new Microwave.Microwave(drive, power, notification); Console.WriteLine("Разморозим"); microwave.Defrost(); Console.WriteLine(); Console.WriteLine("Подогреем"); microwave.Heating();

Результат будет следующий:


Книга GoF описывает этот паттерн как предоставляющий унифицированный интерфейс к множеству интерфейсов в некоторой подсистеме. Книга "Паттерны проектирования " дает это же толкование и обращает внимание, что, скрывая слож­ность подсистемы, паттерн "Фасад " в то же время предоставляет все возможности подсистемы через удобный для использования интерфейс.

Для простого практического примера того, как работает паттерн "Фасад", пред­ставьте стиральную машину со всего лишь двумя режимами стирки: для сильно загрязненного белья и для слабо загрязненного.

Для каждого режима стиральная машина должна выполнить предопределенный набор операций: установить темпе­ратуру воды, нагреть воду, установить длительность цикла стирки, добавить сти­ральный порошок, добавить отбеливающее средство, добавить смягчитель ткани и т.д. Каждый режим требует различного набора инструкций по стирке (разное количество стирального порошка, более высокая/низкая температура, более долгий/короткий цикл отжима и т.д.).

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

Пользователь стиральной машины не должен думать о сложной логике стирки вещей (выбирать температуру, длитель­ность цикла и т.д.). Единственное, что должен сделать пользователь - решить, сильно загрязнено белье или нет. В этом состоит сущность паттерна "Фасад" при­менительно к конструкции стиральных машин.

Паттерн "Фасад" обычно реализуется в следующих целях и случаях:

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

Кстати, фасады также иногда реализуют как абстрактные фабрики-одиночки.

Диаграмма классов фасада . Как можно увидеть на диаграмме классов на рис.3.1 , паттерн "Фасад" предоставляет простой интерфейс для базовой системы, инкап­сулируя сложную логику.

Рис 3.1 . Диаграмма классов паттерна "Фасад".

Перед прочтением ознакомьтесь с , в котором описаны принятые соглашения и понятия. Данная статья дополняется с некоторой периодичностью, так что если вы ее читали ранее, не факт что данные не изменились.

Facade (Фасад) относиться к классу структурных паттернов. Представляет собой унифицированный интерфейс вместо набора интерфейсов некоторой подсистемы. Паттерн фасад определяет интерфейс более высокого уровня, который упрощает использование подсистем.

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

Это один из тех паттернов, у которого нет четкой реализации, так как она зависит от конкретной системы. В общем случае нам надо выполнить такое преобразование:

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

Ниже приведен набросок одной из реализаций:

/** * SystemA */ class Bank { public function OpenTransaction() {} public function CloseTransaction() {} public function transferMoney($amount) {} } /** * SystemB */ class Client { public function OpenTransaction() {} public function CloseTransaction() {} public function transferMoney($amount) {} } /** * SystemC */ class Log { public function logTransaction() {} } class Facade { public function transfer($amount) { $Bank = new Bank(); $Client = new Client(); $Log = new Log(); $Bank->OpenTransaction(); $Client->OpenTransaction(); $Log->logTransaction("Transaction open"); $Bank->transferMoney(-$amount); $Log->logTransaction("Transfer money from bank"); $Client->transferMoney($amount); $Log->logTransaction("Transfer money to client"); $Bank->CloseTransaction(); $Client->CloseTransaction(); $Log->logTransaction("Transaction close"); } } // Client code $Transfer = new Facade(); $Transfer->transfer(1000);