Factory em Zig
O padrão Factory encapsula a lógica de criação de objetos, permitindo que o código cliente crie instâncias sem conhecer os detalhes de implementação. Em Zig, esse padrão é elegantemente implementado usando comptime, tagged unions e funções de inicialização.
Quando Usar
- Criação de objetos depende de configuração ou parâmetros de runtime
- Diferentes implementações de uma mesma interface
- Encapsular lógica complexa de inicialização
- Criar objetos para diferentes plataformas ou backends
Factory Function Simples
const std = @import("std");
const Transporte = union(enum) {
carro: Carro,
bicicleta: Bicicleta,
onibus: Onibus,
const Carro = struct { velocidade_max: u32 = 120, assentos: u8 = 5 };
const Bicicleta = struct { velocidade_max: u32 = 30, assentos: u8 = 1 };
const Onibus = struct { velocidade_max: u32 = 80, assentos: u8 = 40 };
pub fn criar(tipo: []const u8) !Transporte {
if (std.mem.eql(u8, tipo, "carro")) return .{ .carro = .{} };
if (std.mem.eql(u8, tipo, "bicicleta")) return .{ .bicicleta = .{} };
if (std.mem.eql(u8, tipo, "onibus")) return .{ .onibus = .{} };
return error.TipoDesconhecido;
}
pub fn velocidadeMax(self: Transporte) u32 {
return switch (self) {
.carro => |c| c.velocidade_max,
.bicicleta => |b| b.velocidade_max,
.onibus => |o| o.velocidade_max,
};
}
pub fn assentos(self: Transporte) u8 {
return switch (self) {
.carro => |c| c.assentos,
.bicicleta => |b| b.assentos,
.onibus => |o| o.assentos,
};
}
};
pub fn main() !void {
const t = try Transporte.criar("carro");
std.debug.print("Velocidade máx: {d} km/h\n", .{t.velocidadeMax()});
std.debug.print("Assentos: {d}\n", .{t.assentos()});
}
Factory Genérica com comptime
const std = @import("std");
fn Serializador(comptime formato: []const u8) type {
if (std.mem.eql(u8, formato, "json")) {
return struct {
pub fn serializar(dados: anytype, writer: anytype) !void {
try std.json.stringify(dados, .{}, writer);
}
};
} else if (std.mem.eql(u8, formato, "csv")) {
return struct {
pub fn serializar(dados: anytype, writer: anytype) !void {
const fields = std.meta.fields(@TypeOf(dados));
inline for (fields, 0..) |campo, i| {
if (i > 0) try writer.writeAll(",");
try writer.print("{any}", .{@field(dados, campo.name)});
}
try writer.writeAll("\n");
}
};
} else {
@compileError("Formato não suportado: " ++ formato);
}
}
// Uso — tipo resolvido em comptime
const JsonSerializer = Serializador("json");
const CsvSerializer = Serializador("csv");
Factory com Allocator
const std = @import("std");
const Conexao = struct {
host: []const u8,
porta: u16,
allocator: std.mem.Allocator,
pub fn criar(allocator: std.mem.Allocator, config: Config) !*Conexao {
const conn = try allocator.create(Conexao);
conn.* = .{
.host = try allocator.dupe(u8, config.host),
.porta = config.porta,
.allocator = allocator,
};
return conn;
}
pub fn destruir(self: *Conexao) void {
self.allocator.free(self.host);
self.allocator.destroy(self);
}
};
const Config = struct {
host: []const u8 = "localhost",
porta: u16 = 5432,
tipo: []const u8 = "postgres",
};
fn criarConexao(allocator: std.mem.Allocator, config: Config) !*Conexao {
// Factory pode escolher implementação baseada no config
return Conexao.criar(allocator, config);
}
Quando Evitar
- Objetos simples que não precisam de lógica de criação complexa
- Quando a construção direta com
.{ ... }é clara o suficiente - Abstrações desnecessárias que adicionam complexidade sem benefício
Veja Também
- Builder — Construção passo a passo de objetos complexos
- Singleton — Garantir instância única
- Comptime — Factory usando metaprogramação
- Structs — Inicialização de structs em Zig
- Enums e Unions — Tagged unions para polimorfismo