Interface Segregation Principle (ISP)¶
İstemciler kullanmadıkları metodlara bağımlı olmamalıdır; şişkin interface’ler gereksiz bağımlılıklara ve boş implementasyonlara yol açar.
1. Şişkin Interface (Fat Interface)¶
❌ Yanlış Kullanım: Tüm CRUD işlemlerini tek interface’e toplamak.
public interface IUserRepository
{
Task<User> GetByIdAsync(int id);
Task<IEnumerable<User>> GetAllAsync();
Task AddAsync(User user);
Task UpdateAsync(User user);
Task DeleteAsync(int id);
Task<User> GetByEmailAsync(string email);
Task<IEnumerable<User>> SearchAsync(string query);
Task BulkInsertAsync(IEnumerable<User> users);
Task ExportToCsvAsync(string path);
}
✅ İdeal Kullanım: Sorumluluğa göre interface’leri ayırın.
public interface IUserReader
{
Task<User> GetByIdAsync(int id);
Task<User> GetByEmailAsync(string email);
Task<IEnumerable<User>> SearchAsync(string query);
}
public interface IUserWriter
{
Task AddAsync(User user);
Task UpdateAsync(User user);
Task DeleteAsync(int id);
}
public interface IUserBulkOperations
{
Task BulkInsertAsync(IEnumerable<User> users);
Task ExportToCsvAsync(string path);
}
2. Boş Implementasyonlara Zorlama¶
❌ Yanlış Kullanım: Kullanılmayan metodları boş bırakmak zorunda kalmak.
public interface IMessageBroker
{
Task PublishAsync(string topic, object message);
Task SubscribeAsync(string topic, Action<object> handler);
Task AcknowledgeAsync(string messageId);
Task RejectAsync(string messageId);
}
public class FireAndForgetPublisher : IMessageBroker
{
public Task PublishAsync(string topic, object message) { /* ... */ }
public Task SubscribeAsync(string topic, Action<object> handler) => Task.CompletedTask; // Kullanılmıyor
public Task AcknowledgeAsync(string messageId) => Task.CompletedTask; // Kullanılmıyor
public Task RejectAsync(string messageId) => Task.CompletedTask; // Kullanılmıyor
}
✅ İdeal Kullanım: Publisher ve Subscriber interface’lerini ayırın.
public interface IMessagePublisher
{
Task PublishAsync(string topic, object message);
}
public interface IMessageSubscriber
{
Task SubscribeAsync(string topic, Action<object> handler);
Task AcknowledgeAsync(string messageId);
Task RejectAsync(string messageId);
}
public class FireAndForgetPublisher : IMessagePublisher
{
public Task PublishAsync(string topic, object message) { /* ... */ }
}
3. Servis Interface’inde Rol Karışımı¶
❌ Yanlış Kullanım: Admin ve kullanıcı işlemlerini aynı interface’de toplamak.
public interface IProductService
{
Task<Product> GetByIdAsync(int id);
Task<IEnumerable<Product>> SearchAsync(string query);
Task CreateAsync(Product product);
Task UpdateAsync(Product product);
Task DeleteAsync(int id);
Task ApproveAsync(int id);
Task RejectAsync(int id);
Task BulkDeleteAsync(IEnumerable<int> ids);
}
✅ İdeal Kullanım: Rol bazlı interface’ler tanımlayın.
public interface IProductQueryService
{
Task<Product> GetByIdAsync(int id);
Task<IEnumerable<Product>> SearchAsync(string query);
}
public interface IProductManagementService
{
Task CreateAsync(Product product);
Task UpdateAsync(Product product);
Task DeleteAsync(int id);
}
public interface IProductAdminService
{
Task ApproveAsync(int id);
Task RejectAsync(int id);
Task BulkDeleteAsync(IEnumerable<int> ids);
}
4. Generic Interface’de Gereksiz Metod¶
❌ Yanlış Kullanım: Her entity türü için geçerli olmayan metodları generic interface’e koymak.
public interface IEntity
{
int Id { get; set; }
DateTime CreatedAt { get; set; }
DateTime? UpdatedAt { get; set; }
string CreatedBy { get; set; }
bool IsDeleted { get; set; }
void SoftDelete();
void Restore();
}
// Audit log entity'sinin soft delete'e ihtiyacı yok
public class AuditLog : IEntity
{
public void SoftDelete() => throw new NotSupportedException();
public void Restore() => throw new NotSupportedException();
// ...
}
✅ İdeal Kullanım: İlgili davranışları ayrı interface’lere ayırın.
public interface IEntity
{
int Id { get; set; }
}
public interface IAuditable
{
DateTime CreatedAt { get; set; }
string CreatedBy { get; set; }
}
public interface ISoftDeletable
{
bool IsDeleted { get; set; }
void SoftDelete();
void Restore();
}
public class Order : IEntity, IAuditable, ISoftDeletable { /* ... */ }
public class AuditLog : IEntity, IAuditable { /* ... */ }
5. Marker Interface Yerine Attribute Kullanmamak¶
❌ Yanlış Kullanım: Boş marker interface’ler ile gereksiz bağımlılık oluşturmak.
public interface ICacheable { }
public interface ILoggable { }
public interface IAuditable { }
public class ProductService : IProductService, ICacheable, ILoggable, IAuditable
{
// ICacheable, ILoggable, IAuditable hiçbir metod tanımlamıyor
}
✅ İdeal Kullanım: Metadata için attribute kullanın.
[Cacheable(Duration = 300)]
[Auditable]
public class ProductService : IProductService
{
// ...
}
[AttributeUsage(AttributeTargets.Class)]
public class CacheableAttribute : Attribute
{
public int Duration { get; set; }
}