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
- Adapter — Converter entre interfaces
- Builder — Construção passo a passo
- Decorator — Adicionar comportamento incremental
- Receitas — Exemplos de APIs simplificadas
- FAQ Produção — Arquitetura de aplicações