Фасад — это структурный паттерн проектирования, который предоставляет простой интерфейс к сложной системе классов, библиотеке или фреймворку.
Проблема
Вашему коду приходится работать с большим количеством объектов некой сложной библиотеки или фреймворка. Вы должны самостоятельно инициализировать эти объекты, следить за правильным порядком зависимостей и так далее.
В результате бизнес-логика ваших классов тесно переплетается с деталями реализации сторонних классов. Такой код довольно сложно понимать и поддерживать.
Решение
Фасад — это простой интерфейс для работы со сложной подсистемой, содержащей множество классов. Фасад может иметь урезанный интерфейс, не имеющий 100% функциональности, которой можно достичь, используя сложную подсистему напрямую. Но он предоставляет именно те фичи, которые нужны клиенту, и скрывает все остальные.
Фасад полезен, если вы используете какую-то сложную библиотеку со множеством подвижных частей, но вам нужна только часть её возможностей.
К примеру, программа, заливающая видео котиков в социальные сети, может использовать профессиональную библиотеку сжатия видео. Но все, что нужно клиентскому коду этой программы — простой метод encode(filename, format). Создав класс с таким методом, вы реализуете свой первый фасад.
Аналогия из жизни
Пример телефонного заказа.
Когда вы звоните в магазин и делаете заказ по телефону, сотрудник службы поддержки является вашим фасадом ко всем службам и отделам магазина. Он предоставляет вам упрощённый интерфейс к системе создания заказа, платёжной системе и отделу доставки.
Структура
Фасад предоставляет быстрый доступ к определённой функциональности подсистемы. Он «знает», каким классам нужно переадресовать запрос, и какие данные для этого нужны.
Дополнительный фасад можно ввести, чтобы не «захламлять» единственный фасад разнородной функциональностью. Он может использоваться как клиентом, так и другими фасадами.
Сложная подсистема состоит из множества разнообразных классов. Для того, чтобы заставить их что-то делать, нужно знать подробности устройства подсистемы, порядок инициализации объектов и так далее.
Классы подсистемы не знают о существовании фасада и работают друг с другом напрямую.
Клиент использует фасад вместо прямой работы с объектами сложной подсистемы.
Псевдокод
В этом примере Фасад упрощает работу со сложным фреймворком видеоконвертации.
Пример изоляции множества зависимостей в одном фасаде.
Вместо непосредственной работы с дюжиной классов, фасад предоставляет коду приложения единственный метод для конвертации видео, который сам заботится о том, чтобы правильно сконфигурировать нужные объекты фреймворка и получить требуемый результат.
// Классы сложного стороннего фреймворка конвертации видео. Мы
// не контролируем этот код, поэтому не можем его упростить.
class VideoFile
// ...
class OggCompressionCodec
// ...
class MPEG4CompressionCodec
// ...
class CodecFactory
// ...
class BitrateReader
// ...
class AudioMixer
// ...
// Вместо этого мы создаём Фасад — простой интерфейс для работы
// со сложным фреймворком. Фасад не имеет всей функциональности
// фреймворка, но зато скрывает его сложность от клиентов.
class VideoConverter is
method convert(filename, format):File is
file = new VideoFile(filename)
sourceCodec = (new CodecFactory).extract(file)
if (format == "mp4")
destinationCodec = new MPEG4CompressionCodec()
else
destinationCodec = new OggCompressionCodec()
buffer = BitrateReader.read(filename, sourceCodec)
result = BitrateReader.convert(buffer, destinationCodec)
result = (new AudioMixer()).fix(result)
return new File(result)
// Приложение не зависит от сложного фреймворка конвертации
// видео. Кстати, если вы вдруг решите сменить фреймворк, вам
// нужно будет переписать только класс фасада.
class Application is
method main() is
convertor = new VideoConverter()
mp4 = convertor.convert("funny-cats-video.ogg", "mp4")
mp4.save()
Применимость
Когда вам нужно представить простой или урезанный интерфейс к сложной подсистеме.
Часто подсистемы усложняются по мере развития программы. Применение большинства паттернов приводит к появлению меньших классов, но в бóльшем количестве. Такую подсистему проще повторно использовать, настраивая её каждый раз под конкретные нужды, но вместе с тем, применять подсистему без настройки становится труднее. Фасад предлагает определённый вид системы по умолчанию, устраивающий большинство клиентов.
Когда вы хотите разложить подсистему на отдельные слои.
Используйте фасады для определения точек входа на каждый уровень подсистемы. Если подсистемы зависят друг от друга, то зависимость можно упростить, разрешив подсистемам обмениваться информацией только через фасады.
Например, возьмём ту же сложную систему видеоконвертации. Вы хотите разбить её на слои работы с аудио и видео. Для каждой из этих частей можно попытаться создать фасад и заставить классы аудио и видео обработки общаться друг с другом через эти фасады, а не напрямую.
Шаги реализации
Определите, можно ли создать более простой интерфейс, чем тот, который предоставляет сложная подсистема. Вы на правильном пути, если этот интерфейс избавит клиента от необходимости знать о подробностях подсистемы.
Создайте класс фасада, реализующий этот интерфейс. Он должен переадресовывать вызовы клиента нужным объектам подсистемы. Фасад должен будет позаботиться о том, чтобы правильно инициализировать объекты подсистемы.
Вы получите максимум пользы, если клиент будет работать только с фасадом. В этом случае изменения в подсистеме будут затрагивать только код фасада, а клиентский код останется рабочим.
Если ответственность фасада начинает размываться, подумайте о введении дополнительных фасадов.
Преимущества и недостатки
Преимущества
Изолирует клиентов от компонентов сложной подсистемы.
Недостатки
Фасад рискует стать божественным объектом, привязанным ко всем классам программы.
Примеры реализации паттерна
Python
Сложность: 1/3
Популярность: 2/3
Применимость: Паттерн часто встречается в клиентских приложениях, написанных на Python, которые используют классы-фасады для упрощения работы со сложными библиотеки или API.
Признаки применения паттерна: Фасад угадывается в классе, который имеет простой интерфейс, но делегирует основную часть работы другим классам. Чаще всего, фасады сами следят за жизненным циклом объектов сложной системы.
Этот пример показывает структуру паттерна Фасад, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
from__future__importannotationsclassFacade:""" Класс Фасада предоставляет простой интерфейс для сложной логики одной или нескольких подсистем. Фасад делегирует запросы клиентов соответствующим объектам внутри подсистемы. Фасад также отвечает за управление их жизненным циклом. Все это защищает клиента от нежелательной сложности подсистемы. """def__init__(self,subsystem1:Subsystem1,subsystem2:Subsystem2)->None:""" В зависимости от потребностей вашего приложения вы можете предоставить Фасаду существующие объекты подсистемы или заставить Фасад создать их самостоятельно. """self._subsystem1=subsystem1orSubsystem1()self._subsystem2=subsystem2orSubsystem2()defoperation(self)->str:""" Методы Фасада удобны для быстрого доступа к сложной функциональности подсистем. Однако клиенты получают только часть возможностей подсистемы. """results=[]results.append("Facade initializes subsystems:")results.append(self._subsystem1.operation1())results.append(self._subsystem2.operation1())results.append("Facade orders subsystems to perform the "+"action:")results.append(self._subsystem1.operation_n())results.append(self._subsystem2.operation_z())return"\n".join(results)classSubsystem1:""" Подсистема может принимать запросы либо от фасада, либо от клиента напрямую. В любом случае, для Подсистемы Фасад – это ещё один клиент, и он не является частью Подсистемы. """defoperation1(self)->str:return"Subsystem1: Ready!"# ...defoperation_n(self)->str:return"Subsystem1: Go!"classSubsystem2:""" Некоторые фасады могут работать с разными подсистемами одновременно. """defoperation1(self)->str:return"Subsystem2: Get ready!"# ...defoperation_z(self)->str:return"Subsystem2: Fire!"defclient_code(facade:Facade)->None:""" Клиентский код работает со сложными подсистемами через простой интерфейс, предоставляемый Фасадом. Когда фасад управляет жизненным циклом подсистемы, клиент может даже не знать о существовании подсистемы. Такой подход позволяет держать сложность под контролем. """print(facade.operation(),end="")if__name__=="__main__":# В клиентском коде могут быть уже созданы некоторые объекты# подсистемы. В этом случае может оказаться целесообразным# инициализировать Фасад с этими объектами вместо того, чтобы# позволить Фасаду создавать новые экземпляры.subsystem1=Subsystem1()subsystem2=Subsystem2()facade=Facade(subsystem1,subsystem2)client_code(facade)
Применимость: Паттерн часто встречается в клиентских приложениях, написанных на PHP, которые используют классы-фасады для упрощения работы со сложными библиотеки или API.
Признаки применения паттерна: Фасад угадывается в классе, который имеет простой интерфейс, но делегирует основную часть работы другим классам. Чаще всего, фасады сами следят за жизненным циклом объектов сложной системы.
Этот пример показывает структуру паттерна Фасад, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
После ознакомления со структурой, вам будет легче воспринимать второй пример, который рассматривает реальный случай использования паттерна в мире PHP.
<?php/*** Класс Фасада предоставляет простой интерфейс для сложной логики одной или* нескольких подсистем. Фасад делегирует запросы клиентов соответствующим* объектам внутри подсистемы. Фасад также отвечает за управление их жизненным* циклом. Все это защищает клиента от нежелательной сложности подсистемы.*/classFacade{protected$subsystem1;protected$subsystem2;/** * В зависимости от потребностей вашего приложения вы можете предоставить * Фасаду существующие объекты подсистемы или заставить Фасад создать их * самостоятельно. */publicfunction__construct(Subsystem1$subsystem1=null,Subsystem2$subsystem2=null){$this->subsystem1=$subsystem1?:newSubsystem1();$this->subsystem2=$subsystem2?:newSubsystem2();}/** * Методы Фасада удобны для быстрого доступа к сложной функциональности * подсистем. Однако клиенты получают только часть возможностей подсистемы. */publicfunctionoperation():string{$result="Facade initializes subsystems:\n";$result.=$this->subsystem1->operation1();$result.=$this->subsystem2->operation1();$result.="Facade orders subsystems to perform the action:\n";$result.=$this->subsystem1->operationN();$result.=$this->subsystem2->operationZ();return$result;}}/*** Подсистема может принимать запросы либо от фасада, либо от клиента напрямую.* В любом случае, для Подсистемы Фасад – это еще один клиент, и он не является* частью Подсистемы.*/classSubsystem1{publicfunctionoperation1():string{return"Subsystem1: Ready!\n";}// ...publicfunctionoperationN():string{return"Subsystem1: Go!\n";}}/*** Некоторые фасады могут работать с разными подсистемами одновременно.*/classSubsystem2{publicfunctionoperation1():string{return"Subsystem2: Get ready!\n";}// ...publicfunctionoperationZ():string{return"Subsystem2: Fire!\n";}}/*** Клиентский код работает со сложными подсистемами через простой интерфейс,* предоставляемый Фасадом. Когда фасад управляет жизненным циклом подсистемы,* клиент может даже не знать о существовании подсистемы. Такой подход позволяет* держать сложность под контролем.*/functionclientCode(Facade$facade){// ...echo$facade->operation();// ...}/*** В клиентском коде могут быть уже созданы некоторые объекты подсистемы. В этом* случае может оказаться целесообразным инициализировать Фасад с этими* объектами вместо того, чтобы позволить Фасаду создавать новые экземпляры.*/$subsystem1=newSubsystem1();$subsystem2=newSubsystem2();$facade=newFacade($subsystem1,$subsystem2);clientCode($facade);
Думайте о Фасаде как о «адаптере-упрощателе» для некой сложной подсистемы. Фасад изолирует сложность в рамках одного класса и позволяет остальному коду приложения использовать простой интерфейс.
В этом примере Фасад скрывает сложность API YouTube и библиотеки FFmpeg от клиентского кода. Вместо того, чтобы работать с десятками классов, клиент использует простой метод Фасада.
<?php/*** Фасад предоставляет единый метод загрузки видео с YouTube. Этот метод* скрывает всю сложность сетевого уровня PHP, API YouTube и библиотеки* преобразования видео (FFmpeg).*/classYouTubeDownloader{protected$youtube;protected$ffmpeg;/** * Бывает удобным сделать Фасад ответственным за управление жизненным циклом * используемой подсистемы. */publicfunction__construct(string$youtubeApiKey){$this->youtube=newYouTube($youtubeApiKey);$this->ffmpeg=newFFMpeg();}/** * Фасад предоставляет простой метод загрузки видео и кодирования его в * целевой формат (для простоты понимания примера реальный код * закомментирован). */publicfunctiondownloadVideo(string$url):void{echo"Fetching video metadata from youtube...\n";// $title = $this->youtube->fetchVideo($url)->getTitle();echo"Saving video file to a temporary file...\n";// $this->youtube->saveAs($url, "video.mpg");echo"Processing source video...\n";// $video = $this->ffmpeg->open('video.mpg');echo"Normalizing and resizing the video to smaller dimensions...\n";// $video// ->filters()// ->resize(new FFMpeg\Coordinate\Dimension(320, 240))// ->synchronize();echo"Capturing preview image...\n";// $video// ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10))// ->save($title . 'frame.jpg');echo"Saving video in target formats...\n";// $video// ->save(new FFMpeg\Format\Video\X264(), $title . '.mp4')// ->save(new FFMpeg\Format\Video\WMV(), $title . '.wmv')// ->save(new FFMpeg\Format\Video\WebM(), $title . '.webm');echo"Done!\n";}}/*** Подсистема API YouTube.*/classYouTube{publicfunctionfetchVideo():string{/* ... */}publicfunctionsaveAs(string$path):void{/* ... */}// ...дополнительные методы и классы...}/*** Подсистема FFmpeg (сложная библиотека работы с видео/аудио).*/classFFMpeg{publicstaticfunctioncreate():FFMpeg{/* ... */}publicfunctionopen(string$video):void{/* ... */}// ...more methods and classes... RU: ...дополнительные методы и классы...}classFFMpegVideo{publicfunctionfilters():self{/* ... */}publicfunctionresize():self{/* ... */}publicfunctionsynchronize():self{/* ... */}publicfunctionframe():self{/* ... */}publicfunctionsave(string$path):self{/* ... */}// ...more methods and classes... RU: ...дополнительные методы и классы...}/*** Клиентский код не зависит от классов подсистем. Любые изменения внутри кода* подсистем не будут влиять на клиентский код. Вам нужно будет всего лишь* обновить Фасад.*/functionclientCode(YouTubeDownloader$facade){// ...$facade->downloadVideo("https://www.youtube.com/watch?v=QH2-TGUlwu4");// ...}$facade=newYouTubeDownloader("APIKEY-XXXXXXXXX");clientCode($facade);
Оформление заказа требует координации нескольких подсистем. Реализуйте ФасадOrderFacade с методом place_order(user_id, items, payment_method), который скрывает взаимодействие с InventoryService, PaymentService, ShippingService и NotificationService. Клиентский код должен вызывать один метод фасада, не зная о внутренних подсистемах.
<?php// Подсистемы (изменять нельзя)classInventoryService{publicfunctioncheckAvailability(int$itemId,int$qty):bool{echo"[Inventory] Проверка наличия товара #{$itemId}, кол-во: {$qty}\n";returntrue;}publicfunctionreserve(int$itemId,int$qty):string{$reservationId="RES-{$itemId}-{$qty}";echo"[Inventory] Зарезервировано: {$reservationId}\n";return$reservationId;}publicfunctionrelease(string$reservationId):void{echo"[Inventory] Резервация {$reservationId} снята\n";}}classPaymentService{publicfunctionauthorize(int$userId,float$amount,string$method):string{echo"[Payment] Авторизация {$amount} руб. для #{$userId} через {$method}\n";return"AUTH-{$userId}-".(int)$amount;}publicfunctioncapture(string$authId):string{echo"[Payment] Списание по авторизации {$authId}\n";return"TXN-{$authId}";}publicfunctionrefund(string$transactionId):void{echo"[Payment] Возврат по транзакции {$transactionId}\n";}}classShippingService{publicfunctioncalculateCost(array$items):float{$cost=count($items)*150.0;echo"[Shipping] Стоимость доставки: {$cost} руб.\n";return$cost;}publicfunctioncreateShipment(int$userId,array$items):string{$shipmentId="SHIP-{$userId}";echo"[Shipping] Создана отправка: {$shipmentId}\n";return$shipmentId;}}classNotificationService{publicfunctionsendConfirmation(int$userId,string$orderId):void{echo"[Notify] Подтверждение заказа {$orderId} отправлено пользователю #{$userId}\n";}publicfunctionsendFailure(int$userId,string$reason):void{echo"[Notify] Уведомление об ошибке для #{$userId}: {$reason}\n";}}// TODO: реализовать фасад OrderFacade:// - __construct() — создаёт экземпляры всех подсистем// - placeOrder(int $userId, array $items, string $paymentMethod): ?string// Шаги:// 1. Проверить наличие и зарезервировать каждый товар// 2. Рассчитать доставку и итоговую сумму// 3. Авторизовать и списать оплату// 4. Создать отправку// 5. Уведомить пользователя// При ошибке на любом шаге — откатить резервации и уведомить об ошибке// Клиентский код// $facade = new OrderFacade();// $orderId = $facade->placeOrder(// userId: 42,// items: [['id' => 1, 'qty' => 2, 'price' => 500], ['id' => 3, 'qty' => 1, 'price' => 1200]],// paymentMethod: 'card'// );// echo "\nЗаказ создан: {$orderId}\n";
Задача 2. Фасад аутентификации
Процесс входа в систему включает несколько шагов. Реализуйте ФасадAuthFacade с методами login(email, password), logout(token) и register(name, email, password). Фасад должен координировать UserRepository, PasswordHasher, TokenService и SessionStore, скрывая их от клиентского кода.
<?php// Подсистемы (изменять нельзя)classUser{publicfunction__construct(publicint$id,publicstring$name,publicstring$email,publicstring$passwordHash,){}}classUserRepository{privatearray$users=[];privateint$nextId=1;publicfunctionfindByEmail(string$email):?User{return$this->users[$email]??null;}publicfunctionsave(User$user):User{$this->users[$user->email]=$user;echo"[UserRepo] Пользователь сохранён: {$user->email}\n";return$user;}publicfunctionnextId():int{return$this->nextId++;}}classPasswordHasher{publicfunctionhash(string$plain):string{returnhash('sha256',$plain);}publicfunctionverify(string$plain,string$hashed):bool{return$this->hash($plain)===$hashed;}}classTokenService{publicfunctiongenerate(int$userId):string{$token=bin2hex(random_bytes(16));echo"[Token] Выдан токен для #{$userId}: ".substr($token,0,8)."...\n";return$token;}publicfunctioninvalidate(string$token):void{echo"[Token] Токен ".substr($token,0,8)."... инвалидирован\n";}}classSessionStore{privatearray$sessions=[];publicfunctioncreate(string$token,int$userId):void{$this->sessions[$token]=$userId;echo"[Session] Сессия создана для пользователя #{$userId}\n";}publicfunctiondestroy(string$token):void{unset($this->sessions[$token]);echo"[Session] Сессия удалена\n";}publicfunctiongetUserId(string$token):?int{return$this->sessions[$token]??null;}}// TODO: реализовать фасад AuthFacade:// - __construct() — создаёт экземпляры всех подсистем// - register(name, email, password): string// 1. Проверить, что email не занят// 2. Хэшировать пароль, сохранить пользователя// 3. Выдать токен и создать сессию// Бросать InvalidArgumentException если email уже занят// - login(email, password): string// 1. Найти пользователя, проверить пароль// 2. Выдать токен и создать сессию// Бросать InvalidArgumentException при неверных данных// - logout(token): void — инвалидировать токен и удалить сессию// Клиентский код// $auth = new AuthFacade();// $token = $auth->register('Анна', '[email protected]', 'secret123');// echo "Зарегистрирована, токен: " . substr($token, 0, 8) . "...\n";// $auth->logout($token);// $token2 = $auth->login('[email protected]', 'secret123');// echo "Вошла, токен: " . substr($token2, 0, 8) . "...\n";
Задача 3. Фасад генерации отчётов
Генерация отчёта требует обращения к нескольким подсистемам. Реализуйте ФасадReportFacade с методом generate(report_type, filters, output_format), который координирует DataQueryService, ReportBuilder, ChartGenerator и ExportService. Клиент передаёт только высокоуровневые параметры и получает готовый файл.
<?php// Подсистемы (изменять нельзя)classDataQueryService{publicfunctionquery(string$reportType,array$filters):array{echo"[Query] Получение данных: type={$reportType}\n";return[['label'=>'Январь','value'=>150000],['label'=>'Февраль','value'=>210000],['label'=>'Март','value'=>185000],];}}classReportBuilder{publicfunctionbuild(array$data,string$reportType):array{$total=array_sum(array_column($data,'value'));echo"[Builder] Построение отчёта: ".count($data)." записей, итого {$total}\n";return['type'=>$reportType,'data'=>$data,'total'=>$total];}}classChartGenerator{publicfunctiongenerate(array$report,string$chartType='bar'):string{echo"[Chart] Генерация {$chartType}-диаграммы для {$report['type']}\n";return"<chart type='{$chartType}' total='{$report['total']}'/>";}}classExportService{publicfunctionexport(array$report,string$chart,string$fmt):string{$filename="report_{$report['type']}.{$fmt}";echo"[Export] Экспорт в ".strtoupper($fmt).": {$filename}\n";return$filename;}}// TODO: реализовать фасад ReportFacade:// - __construct() — создаёт экземпляры всех подсистем// - generate(string $reportType, array $filters, string $outputFormat = 'pdf'): string// Шаги:// 1. Запросить данные через DataQueryService// 2. Построить отчёт через ReportBuilder// 3. Сгенерировать диаграмму через ChartGenerator// 4. Экспортировать через ExportService// Вернуть имя итогового файла// Клиентский код — не знает о подсистемах// $facade = new ReportFacade();// $file = $facade->generate(// reportType: 'sales',// filters: ['year' => 2025, 'region' => 'Москва'],// outputFormat: 'pdf'// );// echo "\nГотово: {$file}\n";
Задача 4. Фасад медиаконвертера
Конвертация медиафайлов требует цепочки операций. Реализуйте ФасадMediaConverter с методами convert_video(src, target_format) и convert_audio(src, target_format). Фасад координирует FileReader, CodecDetector, VideoEncoder, AudioEncoder и FileWriter. Клиент не должен знать, какие кодеки используются.
<?php// Подсистемы (изменять нельзя)classFileReader{publicfunctionread(string$path):string{echo"[Reader] Читаю файл: {$path}\n";return'raw_media_data';}}classCodecDetector{publicfunctiondetect(string$data,string$filename):string{$ext=strtolower(pathinfo($filename,PATHINFO_EXTENSION));$map=['mp4'=>'h264','avi'=>'divx','mkv'=>'h265','mp3'=>'mp3','wav'=>'pcm','flac'=>'flac'];$codec=$map[$ext]??'unknown';echo"[Codec] Обнаружен кодек: {$codec}\n";return$codec;}}classVideoEncoder{publicfunctionencode(string$data,string$srcCodec,string$dstFormat):string{echo"[VideoEncoder] {$srcCodec} → {$dstFormat}\n";return'encoded_video';}}classAudioEncoder{publicfunctionencode(string$data,string$srcCodec,string$dstFormat):string{echo"[AudioEncoder] {$srcCodec} → {$dstFormat}\n";return'encoded_audio';}}classFileWriter{publicfunctionwrite(string$data,string$path):void{echo"[Writer] Записываю файл: {$path} (".strlen($data)." байт)\n";}}// TODO: реализовать фасад MediaConverter:// - __construct() — создаёт экземпляры всех подсистем// - convertVideo(string $src, string $targetFormat): string// 1. Прочитать файл// 2. Определить кодек источника// 3. Перекодировать видео// 4. Записать "{имя_без_расширения}.{targetFormat}"// Вернуть путь к выходному файлу// - convertAudio(string $src, string $targetFormat): string// Аналогично, но через AudioEncoder// Клиентский код// $converter = new MediaConverter();// $out1 = $converter->convertVideo('movie.avi', 'mp4');// echo "Результат: {$out1}\n\n";// $out2 = $converter->convertAudio('track.wav', 'mp3');// echo "Результат: {$out2}\n";
Задача 5. Фасад умного дома
Система умного дома состоит из множества независимых подсистем. Реализуйте ФасадSmartHomeFacade со сценариями arrive_home(), leave_home() и night_mode(). Каждый сценарий управляет несколькими подсистемами: LightingSystem, ClimateSystem, SecuritySystem и EntertainmentSystem. Клиент вызывает один метод вместо десяти.
# Подсистемы (изменять нельзя)classLightingSystem:defturn_on(self,zone:str,brightness:int=100)->None:print(f"[Light] {zone}: включён на {brightness}%")defturn_off(self,zone:str)->None:print(f"[Light] {zone}: выключен")defset_scene(self,scene:str)->None:print(f"[Light] Сцена: {scene}")classClimateSystem:defset_temperature(self,celsius:float)->None:print(f"[Climate] Температура установлена: {celsius}°C")defset_mode(self,mode:str)->None:print(f"[Climate] Режим: {mode}")defturn_off(self)->None:print("[Climate] Выключен")classSecuritySystem:defarm(self,mode:str="away")->None:print(f"[Security] Охрана включена: режим {mode}")defdisarm(self)->None:print("[Security] Охрана снята")deflock_doors(self)->None:print("[Security] Все двери заблокированы")defunlock_doors(self)->None:print("[Security] Двери разблокированы")classEntertainmentSystem:defturn_on(self,source:str)->None:print(f"[Entertainment] Включён источник: {source}")defturn_off(self)->None:print("[Entertainment] Выключен")defset_volume(self,level:int)->None:print(f"[Entertainment] Громкость: {level}%")# TODO: реализовать фасад SmartHomeFacade:# - __init__() — создаёт экземпляры всех подсистем# - arrive_home() — сценарий прихода домой:# разблокировать двери, снять охрану, включить свет в прихожей (80%),# установить комфортную температуру (22°C), включить фоновую музыку (30%)# - leave_home() — сценарий ухода из дома:# выключить весь свет, выключить развлечения, установить экономный климат (18°C),# заблокировать двери, включить охрану в режиме "away"# - night_mode() — ночной режим:# выключить свет везде кроме спальни (5%), установить 20°C режим "sleep",# включить охрану в режиме "night", выключить развлечения# Клиентский код# home = SmartHomeFacade()# print("=== Пришли домой ===")# home.arrive_home()# print("\n=== Уходим ===")# home.leave_home()# print("\n=== Ночной режим ===")# home.night_mode()
```php linenums="1"
<?php
// Подсистемы (изменять нельзя)
class LightingSystem {
public function turnOn(string $zone, int \(brightness = 100): void {
echo "[Light] {\)zone}: включён на {$brightness}%\n";
}
public function turnOff(string \(zone): void { echo "[Light] {\)zone}: выключен\n"; }
public function setScene(string \(scene): void { echo "[Light] Сцена: {\)scene}\n"; }
}
class ClimateSystem {
public function setTemperature(float \(celsius): void {
echo "[Climate] Температура: {\)celsius}°C\n";
}
public function setMode(string \(mode): void { echo "[Climate] Режим: {\)mode}\n"; }
public function turnOff(): void { echo "[Climate] Выключен\n"; }
}
class SecuritySystem {
public function arm(string \(mode = 'away'): void { echo "[Security] Охрана: {\)mode}\n"; }
public function disarm(): void { echo "[Security] Охрана снята\n"; }
public function lockDoors(): void { echo "[Security] Двери заблокированы\n"; }
public function unlockDoors(): void { echo "[Security] Двери разблокированы\n"; }
}
class EntertainmentSystem {
public function turnOn(string \(source): void { echo "[Entertainment] Источник: {\)source}\n"; }
public function turnOff(): void { echo "[Entertainment] Выключен\n"; }
public function setVolume(int \(level): void { echo "[Entertainment] Громкость: {\)level}%\n"; }
}
// TODO: реализовать фасад SmartHomeFacade:
// - __construct() — создаёт экземпляры всех подсистем
// - arriveHome() — сценарий прихода домой:
// разблокировать двери, снять охрану, включить свет в прихожей (80%),
// установить 22°C, включить фоновую музыку (30%)
// - leaveHome() — сценарий ухода:
// выключить весь свет, развлечения, установить 18°C, заблокировать, охрана "away"
// - nightMode() — ночной режим:
// выключить свет везде кроме спальни (5%), 20°C режим "sleep",
// охрана "night", выключить развлечения
// Клиентский код
// $home = new SmartHomeFacade();
// echo "=== Пришли домой ===\n";
// $home->arriveHome();
// echo "\n=== Уходим ===\n";
// $home->leaveHome();
// echo "\n=== Ночной режим ===\n";
// $home->nightMode();