Facade (Фасад)

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

Когда применять Facade

  • Когда нужно упростить взаимодействие с большой и сложной системой классов.
  • Когда нужно разделить систему на слои и обеспечить удобное взаимодействие между ними.
  • Когда нужно снизить зависимость клиентского кода от внутренних деталей реализации подсистем.

PlantUML-диаграмма

UML диаграмма Facade

// Подсистема 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 — это удобный интерфейс к сложной системе. Он упрощает взаимодействие, улучшает читаемость и поддержку кода, а также помогает реализовать принципы инкапсуляции и слабой связанности между компонентами приложения.