Factory Pattern¶
Factory deseni, nesne oluşturma mantığını soyutlayarak kodun esnekliğini artırır; yanlış kullanımlarda ise gereksiz karmaşıklık ve bakım zorluğu ortaya çıkar.
1. Switch-Case ile Nesne Oluşturma¶
❌ Yanlış Kullanım: Her yeni tip eklendiğinde factory sınıfını değiştirmek.
public class NotificationFactory
{
public INotification Create(string type)
{
switch (type)
{
case "email": return new EmailNotification();
case "sms": return new SmsNotification();
case "push": return new PushNotification();
default: throw new ArgumentException("Bilinmeyen tip");
}
}
}
✅ İdeal Kullanım: Dictionary tabanlı kayıt sistemi ile OCP’ye uygun factory oluşturun.
public class NotificationFactory
{
private readonly Dictionary<string, Func<INotification>> _creators = new();
public void Register(string type, Func<INotification> creator)
{
_creators[type] = creator;
}
public INotification Create(string type)
{
if (!_creators.TryGetValue(type, out var creator))
throw new ArgumentException($"Bilinmeyen tip: {type}");
return creator();
}
}
2. Factory İçinde Doğrudan Bağımlılık Oluşturma¶
❌ Yanlış Kullanım: Factory içinde bağımlılıkları new ile oluşturmak.
public class PaymentProcessorFactory
{
public IPaymentProcessor Create(string provider)
{
return provider switch
{
"stripe" => new StripeProcessor(new HttpClient(), new Logger()),
"paypal" => new PayPalProcessor(new HttpClient(), new Logger()),
_ => throw new ArgumentException("Bilinmeyen provider")
};
}
}
✅ İdeal Kullanım: DI container ile factory entegrasyonu yapın.
public class PaymentProcessorFactory
{
private readonly IServiceProvider _serviceProvider;
public PaymentProcessorFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IPaymentProcessor Create(string provider)
{
return provider switch
{
"stripe" => _serviceProvider.GetRequiredService<StripeProcessor>(),
"paypal" => _serviceProvider.GetRequiredService<PayPalProcessor>(),
_ => throw new ArgumentException("Bilinmeyen provider")
};
}
}
3. Generic Factory Kullanmamak¶
❌ Yanlış Kullanım: Her entity için ayrı factory sınıfı yazmak.
public class OrderValidatorFactory
{
public IValidator<Order> Create() => new OrderValidator();
}
public class ProductValidatorFactory
{
public IValidator<Product> Create() => new ProductValidator();
}
✅ İdeal Kullanım: Generic factory ile tekrarı ortadan kaldırın.
public interface IValidatorFactory
{
IValidator<T> Create<T>();
}
public class ValidatorFactory : IValidatorFactory
{
private readonly IServiceProvider _serviceProvider;
public ValidatorFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IValidator<T> Create<T>()
{
return _serviceProvider.GetRequiredService<IValidator<T>>();
}
}
4. Abstract Factory Yerine If-Else Zinciri¶
❌ Yanlış Kullanım: İlişkili nesneleri if-else ile oluşturmak.
public class UIComponentFactory
{
public IButton CreateButton(string theme)
{
if (theme == "dark") return new DarkButton();
else return new LightButton();
}
public ITextBox CreateTextBox(string theme)
{
if (theme == "dark") return new DarkTextBox();
else return new LightTextBox();
}
}
✅ İdeal Kullanım: Abstract Factory ile tutarlı nesne aileleri oluşturun.
public interface IThemeFactory
{
IButton CreateButton();
ITextBox CreateTextBox();
}
public class DarkThemeFactory : IThemeFactory
{
public IButton CreateButton() => new DarkButton();
public ITextBox CreateTextBox() => new DarkTextBox();
}
public class LightThemeFactory : IThemeFactory
{
public IButton CreateButton() => new LightButton();
public ITextBox CreateTextBox() => new LightTextBox();
}
5. Factory Method’u Interface ile Soyutlamamak¶
❌ Yanlış Kullanım: Concrete factory sınıfına doğrudan bağımlılık.
public class OrderService
{
private readonly ShippingFactory _factory = new ShippingFactory();
public void Ship(Order order)
{
var shipper = _factory.Create(order.ShippingMethod);
shipper.Ship(order);
}
}
✅ İdeal Kullanım: Factory’yi interface ile soyutlayarak bağımlılığı gevşetin.
public interface IShippingFactory
{
IShipper Create(string method);
}
public class OrderService
{
private readonly IShippingFactory _factory;
public OrderService(IShippingFactory factory)
{
_factory = factory;
}
public void Ship(Order order)
{
var shipper = _factory.Create(order.ShippingMethod);
shipper.Ship(order);
}
}
6. Keyed Services Kullanmamak (.NET 8+)¶
❌ Yanlış Kullanım: Aynı interface’in farklı implementasyonları için manuel factory yazmak.
public class StorageFactory
{
private readonly IServiceProvider _sp;
public StorageFactory(IServiceProvider sp) => _sp = sp;
public IStorage Create(string type) => type switch
{
"blob" => _sp.GetRequiredService<BlobStorage>(),
"local" => _sp.GetRequiredService<LocalStorage>(),
_ => throw new ArgumentException("Bilinmeyen tip")
};
}
✅ İdeal Kullanım: .NET 8 Keyed Services ile doğrudan DI desteği kullanın.
builder.Services.AddKeyedSingleton<IStorage, BlobStorage>("blob");
builder.Services.AddKeyedSingleton<IStorage, LocalStorage>("local");
public class FileService
{
private readonly IStorage _storage;
public FileService([FromKeyedServices("blob")] IStorage storage)
{
_storage = storage;
}
}