CodeLAB
на главную карта сайта обратная связь
каталог | задачи | паттерны | исходники | стат | форумы | ссылки
 гость
искать в
Главная >> Каталог задач >> Паттерны >> Структурные >> Фасад (Facade)

<< назад
распечатать обсудить >>


Фасад (Facade)
реализации: C++, количество: 7

Aвтор: this
Дата: 19.08.2007
Просмотров: 46896
Рейтинг: 0/0,0(0)
+
реализации(исходники) +добавить

Имя

«Паттерн
Facade» codelab.ru codelab.ru источник оригинал

Фасад - паттерн, структурирующий объекты, предоставляя ко всем ним доступ через единый шлюз. codelab.ru источник оригинал codelab.ru

Условия, Задача, Назначение

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

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

источник codelab.ru codelab.ru оригинал

Мотивация

Рассмотрим, например, среду программирования, которая дает приложениям доступ к подсистеме компиляции. В этой подсистеме имеются такие классы, как Scanner (лексический анализатор), Parser (синтаксический анализатор), ProgramNode (узел программы), BytecodeStream (поток байтовых кодов) и ProgramNodeBuilder (строитель узла программы). Все вместе они составляют компилятор. Некоторым специализированным приложениям, возможно, понадобится прямой доступ к этим классам. Но для большинства клиентов компилятора такие детали, как синтаксический разбор и генерация кода, обычно не нужны; им просто требуется откомпилировать некоторую программу. Для таких клиентов применение мощного, но низкоуровневого интерфейса подсистемы компиляции только усложняет задачу. codelab.ru оригинал источник codelab.ru

источник codelab.ru codelab.ru оригинал

Чтобы предоставить интерфейс более высокого уровня, изолирующий клиента от этих классов, в подсистему компиляции включен также класс Compiler (компилятор). Он определяет унифицированный интерфейс ко всем возможностям компилятора. Класс Compiler выступает в роли фасада: предлагает простой интерфейс к более сложной подсистеме. Он «склеивает» классы, реализующие функциональность компилятора, но не скрывает их полностью. Благодаря фасаду компилятора работа большинства программистов облегчается: с классом Compiler можно работать просто как с «черным ящиком». Но т.к. в действительности это совсем не закрытый объект, то те, кому нужен доступ к средствам низкого уровня, также не лишаются его. источник codelab.ru оригинал codelab.ru

Признаки применения, использования паттерна Фасад (Facade)

Используйте паттерн фасад, когда: оригинал источник codelab.ru codelab.ru
  1. Хотите предоставить простой интерфейс к сложной подсистеме.
    Часто подсистемы усложняются по мере развития. Применение большинства паттернов приводит к появлению меньших классов, но в большем количестве. Такую подсистему проще повторно использовать и настраивать под конкретные нужды, но вместе с тем применять подсистему без настройки становится труднее. Фасад предлагает некоторый вид системы по умолчанию, устраивающий большинство клиентов. И лишь те объекты, которым нужны более широкие возможности настройки, могут обратиться напрямую к тому, что находится за фасадом; источник оригинал codelab.ru codelab.ru
  2. Между клиентами и классами реализации абстракции существует много зависимостей.
    Фасад позволит изолировать подсистему как от клиентов, так и от других подсистем, что, в свою очередь, способствует повышению степени независимости и переносимости; codelab.ru codelab.ru оригинал источник
  3. Вы хотите разложить подсистему на отдельные слои: расслоить.
    Используйте фасад для определения точки входа на каждый уровень подсистемы. Если подсистемы зависят друг от друга, то зависимость можно упростить, разрешив подсистемам обмениваться информацией только через фасады. оригинал источник codelab.ru codelab.ru

Решение

codelab.ru оригинал источник codelab.ru

codelab.ru codelab.ru оригинал источник

Участники паттерна Фасад (Facade)

оригинал источник codelab.ru codelab.ru

  1. Facade (Compiler) – фасад.
    Осведомлен о том, каким классам подсистемы адресовать запрос.
    Делегирует запросы клиентов подходящим объектам внутри подсистемы. источник оригинал codelab.ru codelab.ru
  2. Классы подсистемы (Scanner, Parser, ProgramNode и т.д.).
    Реализуют функциональность подсистемы.
    Выполняют работу, запрошенную объектом Facade, которую в свою очередь запросил у Facade-а один из клиентов.
    Ничего не «знают» о существовании самого фасада, то есть не хранят ссылок на него. codelab.ru оригинал источник codelab.ru

Схема использования паттерна Фасад (Facade)

Клиенты общаются с подсистемой, посылая запросы фасаду. Он переадресует их подходящим объектам внутри подсистемы. Хотя основную работу выполняют именно объекты подсистемы, фасаду, возможно, придется преобразовать свой интерфейс в интерфейсы подсистемы.
Клиенты, пользующиеся фасадом, не имеют прямого доступа к объектам подсистемы. codelab.ru codelab.ru оригинал источник

Вопросы, касающиеся реализации паттерна Фасад (Facade)

При реализации фасада следует обратить внимание на следующие вопросы: оригинал codelab.ru codelab.ru источник
  1. Уменьшение степени связанности клиента с подсистемой.
    Степень связанности можно значительно уменьшить, если сделать класс Facade абстрактным. Его конкретные подклассы будут соответствовать различным реализациям подсистемы. Тогда клиенты смогут взаимодействовать с подсистемой через интерфейс абстрактного класса Facade. Это изолирует клиентов от информации о том, какая реализация подсистемы используется.
    Вместо порождения подклассов можно просто конфигурировать объект Facade различными объектами подсистем – передавать ему на начальном этапе (создании) соответствующие объекты. Для настройки фасада достаточно будет заменить потом один или несколько таких объектов, группу взаимосвязанных объектов и т.д. codelab.ru оригинал codelab.ru источник
  2. Открытые и закрытые классы подсистем.
    Подсистема похожа на класс в том отношении, что у обоих есть интерфейсы и оба что-то инкапсулируют. Класс - инкапсулирует состояние и операции, а подсистема - классы. И если полезно различать открытый и закрытый интерфейсы класса, то не менее разумно говорить об открытом и закрытом интерфейсах подсистемы.
    Открытый интерфейс подсистемы состоит из классов, к которым имеют доступ все клиенты; закрытый же интерфейс доступен только для расширения подсистемы. Класс Facade, конечно же, является частью открытого интерфейса, но это не единственная часть. Другие классы подсистемы также могут быть открытыми. Например, в системе компиляции классы Parser и Scanner - часть открытого интерфейса.
    Делать классы подсистемы закрытыми иногда полезно, но это поддерживается немногими объектно-ориентированными языками. Например, и в C++, и в Smalltalk для классов традиционно использовалось глобальное пространство имен. Однако комитет по стандартизации C++ добавил к языку пространства имен, и это позволило разрешать доступ только к открытым классам подсистемы. источник оригинал codelab.ru codelab.ru

Результаты

У паттерна фасад есть следующие преимущества: оригинал источник codelab.ru codelab.ru
  1. Изолирует клиентов от компонентов подсистемы
    Уменьшая тем самым число объектов, с которыми клиентам приходится иметь дело, упрощая работу с подсистемой. codelab.ru источник codelab.ru оригинал
  2. Позволяет ослабить связанность между подсистемой и ее клиентами.
    Зачастую компоненты подсистемы сильно связаны: многие классы из разных частей и слоев системы взаимодействуют с друг другом, меняя один такой класс, приходится перекомпилировать и остальные связанные и т.д. Слабая связанность позволяет видоизменять компоненты, не затрагивая при этом клиентов. Фасады помогают разложить систему на слои и структурировать зависимости между объектами, а также избежать сложных и циклических зависимостей. Это оказывается важным, если клиент и подсистема реализуются независимо.
    Уменьшение числа зависимостей на стадии компиляции чрезвычайно важно в больших системах. Хочется, конечно, чтобы время, уходящее на перекомпиляцию после изменения классов подсистемы, было минимальным. Сокращение числа зависимостей за счет фасадов может уменьшить количество нуждающихся в повторной компиляции файлов после небольшой модификации какой-нибудь важной подсистемы. Фасад может также упростить процесс переноса системы на другие платформы, поскольку уменьшается вероятность того, что в результате изменения одной подсистемы понадобится изменять и все остальные. codelab.ru оригинал источник codelab.ru
  3. Фасад не исключает возможности приложениям напрямую обращаться к классам подсистемы, если это необходимо. Таким образом, у вас есть выбор между простотой и общностью. Совет конечно очевидный: как можно только в крайних случаях прибегайте к прямому взаимодействию с классом за фасадом, лучше если возможно все же как-нибудь обобщить/абстрагировать эту операцию и добавить ее в сам фасад. оригинал codelab.ru codelab.ru источник

Пример

Рассмотрим более подробно, как возвести фасад вокруг подсистемы компиляции.
В подсистеме компиляции определен класс BytecodeStream, который представляет собой поток объектов Bytecode. Объект Bytecode инкапсулирует байтовый код, с помощью которого описываются машинные команды. В этой же подсистеме определен еще класс Token для объектов, инкапсулирующих лексемы языка программирования. источник оригинал codelab.ru codelab.ru

Класс Scanner принимает на входе поток символов и генерирует поток лексем, по одной каждый раз, т.е. он выступает в роли самого первого уровня обработки исходного кода: Scanner. источник оригинал codelab.ru codelab.ru

Далее класс Parser использует класс ProgramNodeBuilder для построения дерева разбора из лексем, возвращенных классом Scanner. оригинал codelab.ru источник codelab.ru

Parser каждый раз вызывает ProgramNodeBuilder для пошагового построения дерева. Взаимодействие этих классов описывается паттерном строитель. codelab.ru источник оригинал codelab.ru

Дерево разбора состоит из экземпляров подклассов класса ProgramNode, таких как StatementNode, ExpressionNode и т.д. Иерархия классов ProgramNodeэто пример паттерна компоновщик. Класс ProgramNode определяет интерфейс для манипулирования узлом программы и его потомками, если таковые имеются. codelab.ru оригинал codelab.ru источник

Операция Traverse (обход) принимает объект CodeGenerator (кодогенератор) в качестве параметра. Подклассы ProgramNode используют этот объект для генерации машинного кода в форме объектов Bytecode, которые помещаются в поток BytecodeStream. Класс CodeGenerator описывается паттерном посетитель. оригинал источник codelab.ru codelab.ru

У CodeGenerator есть подклассы, например StackMachineCodeGenerator и RISCCodeGenerator генерирующие машинный код для различных аппаратных архитектур. codelab.ru codelab.ru источник оригинал

Каждый подкласс ProgramNode реализует операцию Traverse и обращается к ней для обхода своих потомков. Каждый потомок рекурсивно делает то же самое для своих потомков. Например, в подклассе ExpressionNode (узел выражения) операция Traverse определена так: ExpressionNode. codelab.ru источник оригинал codelab.ru

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

В этой реализации жестко «зашит» тип кодогенератора, поэтому программисту не нужно явно задавать целевую архитектуру. Это может быть вполне разумно, когда есть всего одна такая архитектура. Если же это не так, можно было бы изменить конструктор класса Compiler, чтобы он принимал объект CodeGenerator в качестве параметра. Тогда программист указывал бы, каким генератором пользоваться при инстанцировании объекта Compiler. Фасад компилятора можно параметризовать и другими участниками, скажем, объектами Scanner и ProgramNodeBuilder, что повышает гибкость, но в то же время сводит на нет основную цель фасада - предоставление упрощенного интерфейса для наиболее распространенного случая. оригинал codelab.ru источник codelab.ru

  оригинал codelab.ru источник codelab.ru

Известные применения паттерна Фасад (Facade)

Пример компилятора в разделе «Пример кода» навеян идеями из системы компиляции языка ObjectWorks\Smalltalk. источник codelab.ru оригинал codelab.ru
В каркасе ЕТ++ приложение может иметь встроенные средства инспектирования объектов во время выполнения. Они реализуются в отдельной подсистеме, включающей класс фасада с именем ProgrammingEnvironment. Этот фасад определяет такие операции, как InspectObject и InspectClass для доступа к инспекторам. codelab.ru оригинал codelab.ru источник
Приложение, написанное в среде ЕТ++, может также запретить поддержку инспектирования. В таком случае класс ProgrammingEnvironment реализует соответствующие запросы как пустые операции, не делающие ничего. Только подкласс ETProgrammingEnvironment реализует эти операции так, что они отображают окна соответствующих инспекторов. Приложению неизвестно, доступно инспектирование или нет. Здесь мы встречаем пример абстрактной связанности между приложением и подсистемой инспектирования. codelab.ru источник оригинал codelab.ru
В операционной системе Choices фасады используются для составления одного каркаса из нескольких. Ключевыми абстракциями в системе Choices являются процессы, память и адресные пространства. Для каждой из них есть соответствующая подсистема, реализованная в виде каркаса. Это обеспечивает поддержку переноса Choices на разные аппаратные платформы. У двух таких подсистем есть «представители», то есть фасады. Они называются FileSystemlnterface (память) и Domain (адресные пространства). codelab.ru источник codelab.ru оригинал

codelab.ru codelab.ru оригинал источник

Например, для каркаса виртуальной памяти фасадом служит Domain. Класс Domain представляет адресное пространство. Он обеспечивает отображение между виртуальными адресами и смещениями объектов в памяти, файле или на устройстве длительного хранения. Базовые операции класса Domain поддерживают добавление объекта в память по указанному адресу, удаление объекта из памяти и обработку ошибок отсутствия страниц. оригинал источник codelab.ru codelab.ru
Как видно из вышеприведенной диаграммы, внутри подсистемы виртуальной оригинал codelab.ru codelab.ru источник
памяти используются следующие компоненты: оригинал codelab.ru codelab.ru источник
  1. MemoryObject представляет объекты данных; codelab.ru источник оригинал codelab.ru
  2. MemoryObjectCache кэширует данные из объектов MemoryObj ects в физической памяти.
    MemoryObjectCache - это не что иное, как объект Стратегия, в котором локализована политика кэширования; источник оригинал codelab.ru codelab.ru
  3. AddressTranslation инкапсулирует особенности оборудования трансляции адресов. источник codelab.ru оригинал codelab.ru

Операция RepairFault вызывается при возникновении ошибки из-за отсутствия страницы. Domain находит объект в памяти по адресу, где произошла ошибка и делегирует операцию RepairFault кэшу, ассоциированному с этим объектом. Поведение объектов Domain можно настроить, заменив их компоненты. источник codelab.ru оригинал codelab.ru

Родственные паттерны

Паттерн абстрактная фабрика допустимо использовать вместе с фасадом, чтобы предоставить интерфейс для создания объектов подсистем способом, не зависимым от этих подсистем. Абстрактная фабрика вполне может выступать и как альтернатива фасаду, чтобы скрыть платформенно-зависимые классы. оригинал codelab.ru источник codelab.ru
Паттерн посредник аналогичен фасаду в том смысле, что абстрагирует функциональность существующих классов. Однако назначение посредника - абстрагировать произвольное взаимодействие между «сотрудничающими» объектами. источник оригинал codelab.ru codelab.ru
Часто он централизует функциональность, не присущую ни одному из них. Коллеги посредника обмениваются информацией именно с ним, а не напрямую между собой. Напротив, фасад просто абстрагирует интерфейс объектов подсистемы, чтобы ими было проще пользоваться. Он не определяет новой функциональности, и классам подсистемы ничего неизвестно о его существовании. источник codelab.ru оригинал codelab.ru
Обычно требуется только один фасад. Поэтому объекты фасадов часто бывают одиночками. оригинал codelab.ru codelab.ru источник


Реализации: C++(7)   +добавить реализацию

1) Scanner.cpp, code #463[автор:this]
2) Parser.cpp, code #464[автор:this]
3) ProgramNodeBuilder.cpp, code #465[автор:this]
4) ProgramNode.cpp, code #466[автор:this]
5) Compiler.cpp, code #468[автор:this]
6) ExpressionNode.cpp, code #469[автор:this]
7) CodeGenerator.cpp, code #467[автор:this]


<< назад наверх
распечатать обсудить >>

 
каталог | задачи | паттерны | исходники | стат | форумы | карта сайта | контакты | ссылки 
© 2000-2017 CodeLAB Group
  Все права защищены
Страница сгенерирована за 0.034501 секунд
Количество запросов к БД: 14, gzip: 18.7kb/78.9kb(77%)