Паттерн Facade (Фасад) предоставляет простой унифицированный интерфейс к сложной системе классов, библиотек или подсистем. Он скрывает внутреннюю сложность и позволяет клиенту работать с системой через одну удобную точку доступа.
Когда применять Facade
- Когда нужно упростить взаимодействие с большой и сложной системой классов.
- Когда нужно разделить систему на слои и обеспечить удобное взаимодействие между ними.
- Когда нужно снизить зависимость клиентского кода от внутренних деталей реализации подсистем.
PlantUML-диаграмма
// Подсистема 1
public class AudioSystem
{
public void On() => Console.WriteLine("Аудиосистема включена");
public void SetVolume(int level) => Console.WriteLine($"Громкость установлена на {level}");
}
// Подсистема 2
public class VideoSystem
{
public void On() => Console.WriteLine("Видео-проектор включён");
public void SetInput(string source) => Console.WriteLine($"Источник видео: {source}");
}
// Подсистема 3
public class LightingSystem
{
public void DimLights() => Console.WriteLine("Освещение приглушено");
public void Brighten() => Console.WriteLine("Освещение усилено");
}
// Фасад
public class HomeTheaterFacade
{
private AudioSystem _audio;
private VideoSystem _video;
private LightingSystem _lights;
public HomeTheaterFacade(AudioSystem audio, VideoSystem video, LightingSystem lights)
{
_audio = audio;
_video = video;
_lights = lights;
}
public void WatchMovie(string movie)
{
Console.WriteLine($"Подготовка к просмотру фильма: {movie}");
_lights.DimLights();
_video.On();
_video.SetInput("Blu-ray");
_audio.On();
_audio.SetVolume(7);
Console.WriteLine("Фильм запущен! Наслаждайтесь просмотром!");
}
public void EndMovie()
{
Console.WriteLine("Выключение системы...");
_lights.Brighten();
Console.WriteLine("Сеанс завершён.");
}
}
// Клиентский код
class Program
{
static void Main()
{
var audio = new AudioSystem();
var video = new VideoSystem();
var lights = new LightingSystem();
var homeTheater = new HomeTheaterFacade(audio, video, lights);
homeTheater.WatchMovie("Интерстеллар");
homeTheater.EndMovie();
}
}
type AudioSystem struct{}
func (AudioSystem) On() { fmt.Println("Аудиосистема включена") }
func (AudioSystem) SetVolume(level int) { fmt.Printf("Громкость установлена на %d\n", level) }
type VideoSystem struct{}
func (VideoSystem) On() { fmt.Println("Видео-проектор включён") }
func (VideoSystem) SetInput(source string) { fmt.Printf("Источник видео: %s\n", source) }
type LightingSystem struct{}
func (LightingSystem) DimLights() { fmt.Println("Освещение приглушено") }
func (LightingSystem) Brighten() { fmt.Println("Освещение усилено") }
// Фасад
type HomeTheaterFacade struct {
audio AudioSystem
video VideoSystem
lights LightingSystem
}
func (h HomeTheaterFacade) WatchMovie(movie string) {
fmt.Printf("Подготовка к просмотру фильма: %s\n", movie)
h.lights.DimLights()
h.video.On()
h.video.SetInput("Blu-ray")
h.audio.On()
h.audio.SetVolume(7)
fmt.Println("Фильм запущен! Наслаждайтесь просмотром!")
}
func (h HomeTheaterFacade) EndMovie() {
fmt.Println("Выключение системы...")
h.lights.Brighten()
fmt.Println("Сеанс завершён.")
}
func main() {
homeTheater := HomeTheaterFacade{}
homeTheater.WatchMovie("Интерстеллар")
homeTheater.EndMovie()
}
class AudioSystem:
def on(self) -> None:
print("Аудиосистема включена")
def set_volume(self, level: int) -> None:
print(f"Громкость установлена на {level}")
class VideoSystem:
def on(self) -> None:
print("Видео-проектор включён")
def set_input(self, source: str) -> None:
print(f"Источник видео: {source}")
class LightingSystem:
def dim_lights(self) -> None:
print("Освещение приглушено")
def brighten(self) -> None:
print("Освещение усилено")
class HomeTheaterFacade:
def __init__(self, audio: AudioSystem, video: VideoSystem, lights: LightingSystem) -> None:
self._audio = audio
self._video = video
self._lights = lights
def watch_movie(self, movie: str) -> None:
print(f"Подготовка к просмотру фильма: {movie}")
self._lights.dim_lights()
self._video.on()
self._video.set_input("Blu-ray")
self._audio.on()
self._audio.set_volume(7)
print("Фильм запущен! Наслаждайтесь просмотром!")
def end_movie(self) -> None:
print("Выключение системы...")
self._lights.brighten()
print("Сеанс завершён.")
home_theater = HomeTheaterFacade(AudioSystem(), VideoSystem(), LightingSystem())
home_theater.watch_movie("Интерстеллар")
home_theater.end_movie()
class AudioSystem {
on(): void {
console.log("Аудиосистема включена");
}
setVolume(level: number): void {
console.log(`Громкость установлена на ${level}`);
}
}
class VideoSystem {
on(): void {
console.log("Видео-проектор включён");
}
setInput(source: string): void {
console.log(`Источник видео: ${source}`);
}
}
class LightingSystem {
dimLights(): void {
console.log("Освещение приглушено");
}
brighten(): void {
console.log("Освещение усилено");
}
}
class HomeTheaterFacade {
constructor(
private readonly audio: AudioSystem,
private readonly video: VideoSystem,
private readonly lights: LightingSystem,
) {}
watchMovie(movie: string): void {
console.log(`Подготовка к просмотру фильма: ${movie}`);
this.lights.dimLights();
this.video.on();
this.video.setInput("Blu-ray");
this.audio.on();
this.audio.setVolume(7);
console.log("Фильм запущен! Наслаждайтесь просмотром!");
}
endMovie(): void {
console.log("Выключение системы...");
this.lights.brighten();
console.log("Сеанс завершён.");
}
}
const homeTheater = new HomeTheaterFacade(new AudioSystem(), new VideoSystem(), new LightingSystem());
homeTheater.watchMovie("Интерстеллар");
homeTheater.endMovie();
class AudioSystem {
void on() {
System.out.println("Аудиосистема включена");
}
void setVolume(int level) {
System.out.println("Громкость установлена на " + level);
}
}
class VideoSystem {
void on() {
System.out.println("Видео-проектор включён");
}
void setInput(String source) {
System.out.println("Источник видео: " + source);
}
}
class LightingSystem {
void dimLights() {
System.out.println("Освещение приглушено");
}
void brighten() {
System.out.println("Освещение усилено");
}
}
class HomeTheaterFacade {
private final AudioSystem audio;
private final VideoSystem video;
private final LightingSystem lights;
HomeTheaterFacade(AudioSystem audio, VideoSystem video, LightingSystem lights) {
this.audio = audio;
this.video = video;
this.lights = lights;
}
void watchMovie(String movie) {
System.out.println("Подготовка к просмотру фильма: " + movie);
lights.dimLights();
video.on();
video.setInput("Blu-ray");
audio.on();
audio.setVolume(7);
System.out.println("Фильм запущен! Наслаждайтесь просмотром!");
}
void endMovie() {
System.out.println("Выключение системы...");
lights.brighten();
System.out.println("Сеанс завершён.");
}
}
public class Program {
public static void main(String[] args) {
HomeTheaterFacade homeTheater =
new HomeTheaterFacade(new AudioSystem(), new VideoSystem(), new LightingSystem());
homeTheater.watchMovie("Интерстеллар");
homeTheater.endMovie();
}
}
class AudioSystem {
fun on() = println("Аудиосистема включена")
fun setVolume(level: Int) = println("Громкость установлена на $level")
}
class VideoSystem {
fun on() = println("Видео-проектор включён")
fun setInput(source: String) = println("Источник видео: $source")
}
class LightingSystem {
fun dimLights() = println("Освещение приглушено")
fun brighten() = println("Освещение усилено")
}
class HomeTheaterFacade(
private val audio: AudioSystem,
private val video: VideoSystem,
private val lights: LightingSystem,
) {
fun watchMovie(movie: String) {
println("Подготовка к просмотру фильма: $movie")
lights.dimLights()
video.on()
video.setInput("Blu-ray")
audio.on()
audio.setVolume(7)
println("Фильм запущен! Наслаждайтесь просмотром!")
}
fun endMovie() {
println("Выключение системы...")
lights.brighten()
println("Сеанс завершён.")
}
}
fun main() {
val homeTheater = HomeTheaterFacade(AudioSystem(), VideoSystem(), LightingSystem())
homeTheater.watchMovie("Интерстеллар")
homeTheater.endMovie()
}
Плюсы и минусы
| Плюсы | Минусы |
|---|---|
| Изолирует клиентский код от сложных подсистем | Может стать «божественным объектом», если включает слишком много функций |
| Упрощает использование системы | Добавляет дополнительный уровень абстракции |
| Снижает зависимость между клиентом и подсистемами | Не решает проблему высокой сложности подсистем, а лишь скрывает её |
Заключение
Facade — это удобный интерфейс к сложной системе. Он упрощает взаимодействие, улучшает читаемость и поддержку кода, а также помогает реализовать принципы инкапсуляции и слабой связанности между компонентами приложения.