EngineeringSenior DeveloperArchitecture and Patterns

06 - Creational Design Patterns

Patterns quản lý việc tạo objects: Factory, Abstract Factory, Builder, Singleton, Prototype. Khi nào dùng pattern nào, và cách .NET DI thay thế một số patterns.


Factory Method

Vấn đề: Client không cần biết (và KHÔNG NÊN biết) concrete class nào được tạo.

csharp
// Interface
public interface INotification
{
    Task SendAsync(string to, string message);
}

// Implementations
public class EmailNotification : INotification { /* ... */ }
public class SmsNotification : INotification { /* ... */ }

// Factory
public class NotificationFactory
{
    public static INotification Create(string type) => type switch
    {
        "email" => new EmailNotification(),
        "sms"   => new SmsNotification(),
        "push"  => new PushNotification(),
        _       => throw new ArgumentException($"Unknown type: {type}")
    };
}

// .NET DI Alternative: Keyed Services (.NET 8+)
builder.Services.AddKeyedScoped<INotification, EmailNotification>("email");
builder.Services.AddKeyedScoped<INotification, SmsNotification>("sms");
// Inject: [FromKeyedServices("email")] INotification notifier

Dùng khi: Nhiều implementations cho 1 interface, chọn runtime dựa trên config/input.
Dự án: Payment gateways (Stripe, PayPal, Momo), Export engines (PDF, Excel, CSV).


Abstract Factory

csharp
// Tạo FAMILY of related objects
public interface ICloudFactory
{
    IDatabase CreateDatabase();
    IMessageQueue CreateQueue();
    IStorage CreateStorage();
}

public class AzureCloudFactory : ICloudFactory
{
    public IDatabase CreateDatabase() => new AzureSqlDatabase();
    public IMessageQueue CreateQueue() => new AzureServiceBusQueue();
    public IStorage CreateStorage() => new AzureBlobStorage();
}

Dùng khi: Tạo nhóm objects liên quan phải tương thích (Azure stack vs AWS stack).
Dự án: Multi-cloud platforms, cross-platform UI (WPF vs MAUI).


Builder

csharp
// Xây dựng object PHỨC TẠP theo từng bước
public class EmailBuilder
{
    private string _to = "";
    private string _subject = "";
    private string _body = "";
    private List<string> _cc = [];
    private bool _isHtml = false;

    public EmailBuilder To(string to) { _to = to; return this; }
    public EmailBuilder Subject(string s) { _subject = s; return this; }
    public EmailBuilder Body(string b) { _body = b; return this; }
    public EmailBuilder Cc(params string[] cc) { _cc.AddRange(cc); return this; }
    public EmailBuilder AsHtml() { _isHtml = true; return this; }

    public Email Build() => new(_to, _subject, _body, _cc, _isHtml);
}

// Usage (fluent)
var email = new EmailBuilder()
    .To("user@example.com")
    .Subject("Order Confirmed")
    .Body("<h1>Thank you!</h1>")
    .Cc("admin@example.com")
    .AsHtml()
    .Build();

// .NET Built-in Builders: WebApplicationBuilder, HostBuilder, HttpRequestMessage, IConfigurationBuilder

Dùng khi: Constructor >4 tham số, nhiều optional params, construction logic phức tạp.


Singleton

csharp
// ❌ Manual Singleton (cũ, avoid)
public class Logger
{
    private static readonly Lazy<Logger> _instance = new(() => new Logger());
    public static Logger Instance => _instance.Value;
    private Logger() { }
}

// ✅ .NET DI: Singleton đúng cách
builder.Services.AddSingleton<ILogger, SerilogLogger>();
builder.Services.AddSingleton<ICacheService, MemoryCacheService>();
// DI container quản lý lifetime, thread-safe, testable (mock interface)

Lưu ý: Trong .NET modern, hầu hết Singleton nên được quản lý bởi DI container chứ không tự viết.


Prototype

csharp
// Clone object → tránh tạo mới tốn kém
public class ReportTemplate : ICloneable
{
    public object Clone() => MemberwiseClone(); // Shallow copy
}

// .NET Alternative: records with `with` expression
public record ReportSettings(string Title, int PageSize, bool IncludeCharts);
var template = new ReportSettings("Monthly", 50, true);
var customized = template with { Title = "Weekly" }; // Clone + modify

Dùng khi: Object tốn kém để tạo (load config, query DB), cần nhiều bản copy khác nhau chút ít.


Decision Matrix

PatternVấn đề giải quyết.NET DI thay thế?
Factory MethodChọn implementation runtime✅ Keyed Services
Abstract FactoryFamily of related objects🔄 Partial (DI + config)
BuilderComplex object construction❌ Vẫn cần Builder
Singleton1 instance toàn app✅ AddSingleton<>
PrototypeClone object hiệu quả🔄 record with {}