Cheatsheet: Facade em Zig

Facade em Zig

O padrão Facade fornece uma interface simplificada para um subsistema complexo. Em vez de o código cliente interagir com múltiplos módulos e configurações, a fachada oferece uma API coesa e fácil de usar que orquestra os componentes internos.

Quando Usar

  • Subsistema com muitas classes/structs que o cliente não precisa conhecer
  • Simplificar inicialização complexa com múltiplas etapas
  • Fornecer API de alto nível sobre biblioteca de baixo nível
  • Isolar código cliente de mudanças internas no subsistema

Implementação: Facade para Subsistema de Áudio

const std = @import("std");

// --- Subsistemas complexos internos ---

const DecoderAudio = struct {
    formato: []const u8,
    sample_rate: u32,

    pub fn init(formato: []const u8) DecoderAudio {
        return .{ .formato = formato, .sample_rate = 44100 };
    }

    pub fn decodificar(self: *const DecoderAudio, dados: []const u8) []const u8 {
        _ = self;
        return dados; // simplificado
    }
};

const MixerAudio = struct {
    canais: u8,
    volume: f32,

    pub fn init(canais: u8) MixerAudio {
        return .{ .canais = canais, .volume = 1.0 };
    }

    pub fn setVolume(self: *MixerAudio, vol: f32) void {
        self.volume = std.math.clamp(vol, 0.0, 1.0);
    }

    pub fn mixar(self: *const MixerAudio, buffer: []const u8) []const u8 {
        _ = self;
        return buffer;
    }
};

const SaidaAudio = struct {
    dispositivo: []const u8,
    ativo: bool,

    pub fn init(dispositivo: []const u8) SaidaAudio {
        return .{ .dispositivo = dispositivo, .ativo = false };
    }

    pub fn abrir(self: *SaidaAudio) !void {
        self.ativo = true;
    }

    pub fn reproduzir(self: *const SaidaAudio, buffer: []const u8) !void {
        if (!self.ativo) return error.DispositivoFechado;
        _ = buffer;
    }

    pub fn fechar(self: *SaidaAudio) void {
        self.ativo = false;
    }
};

// --- Facade: interface simples ---

const AudioPlayer = struct {
    decoder: DecoderAudio,
    mixer: MixerAudio,
    saida: SaidaAudio,

    pub fn init() !AudioPlayer {
        var player = AudioPlayer{
            .decoder = DecoderAudio.init("mp3"),
            .mixer = MixerAudio.init(2),
            .saida = SaidaAudio.init("default"),
        };
        try player.saida.abrir();
        return player;
    }

    pub fn deinit(self: *AudioPlayer) void {
        self.saida.fechar();
    }

    // API simples — esconde toda a complexidade interna
    pub fn tocar(self: *AudioPlayer, arquivo: []const u8) !void {
        std.debug.print("Tocando: {s}\n", .{arquivo});
        const decodificado = self.decoder.decodificar(arquivo);
        const mixado = self.mixer.mixar(decodificado);
        try self.saida.reproduzir(mixado);
    }

    pub fn setVolume(self: *AudioPlayer, volume: f32) void {
        self.mixer.setVolume(volume);
    }
};

pub fn main() !void {
    // Cliente usa apenas a Facade — simples e limpo
    var player = try AudioPlayer.init();
    defer player.deinit();

    player.setVolume(0.8);
    try player.tocar("musica.mp3");
}

Facade para Inicialização de Aplicação

const std = @import("std");

const App = struct {
    allocator: std.mem.Allocator,
    // subsistemas internos...

    const Opcoes = struct {
        porta: u16 = 8080,
        workers: u8 = 4,
        log_level: []const u8 = "info",
    };

    // Facade: uma única chamada configura tudo
    pub fn init(allocator: std.mem.Allocator, opcoes: Opcoes) !App {
        std.debug.print("Inicializando app na porta {d}...\n", .{opcoes.porta});
        std.debug.print("Workers: {d}, Log: {s}\n", .{ opcoes.workers, opcoes.log_level });
        return .{ .allocator = allocator };
    }

    pub fn deinit(self: *App) void {
        _ = self;
        std.debug.print("App finalizada\n", .{});
    }

    pub fn executar(self: *App) !void {
        _ = self;
        std.debug.print("App em execução...\n", .{});
    }
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    var app = try App.init(gpa.allocator(), .{
        .porta = 3000,
        .log_level = "debug",
    });
    defer app.deinit();

    try app.executar();
}

Quando Evitar

  • Sistemas simples que não precisam de abstração adicional
  • Quando a facade esconde funcionalidade que o cliente precisa
  • Se a facade se torna um “God object” com responsabilidades demais

Veja Também

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.