Repository Design Pattern yazılım geliştirmede kullanılan, Data Source(veri kaynağı) ile uygulama arasında aracı görevi gören structural(yapısal) bir tasarım desenidir.
Data access mantığını programın kalanından soyutlayarak veriye erişmek için tutarlı bir arayüz sağlar. Repository tasarım deseni genellikle veri kaynağında CRUD(Create, Read, Update, Delete) işlemlerini gerçekleştirmek için gereken metotları içerir.
Repository Design Pattern’in Avantajları
- Veri kaynağından bağımsız olarak veriye erişmek için tutarlı ve merkezi bir yol sağlar.
- Veri depolama yönteminin detaylarının değişmesi durumunda kod yapısının kalanını etkilemeden değişiklik yapmaya imkan sağlar.
- Business logic(iş mantığı) ve data access logic(veri erişim mantığı)‘i ayırarak daha temiz ve sürdürülebilir kod yapısına katkıda bulunur.
- Yazılım geliştiricilerin veriye erişmek ve güncellemek gibi işlemler hakkında endişelenmeden iş mantığına odaklanmasına yardımcı olur.
- Uygulamanın farklı bölümlerinden erişilebilecek yeniden kullanılabilir veri erişim metotları sağlar ve kod tekrarlarını azaltır.
Repository Design Pattern’in Dezavantajları
- Basit uygulamalarda repository design pattern kullanımı gereksiz karmaşıklık yaratabilir.
- Gereksiz soyutlamalar karmaşıklığı arttırarak kod okunabilirliğini azaltabilir.
- Doğru şekilde uygulanmaması performans problemlerine sebep olabilir.
- Bütün senaryolar için uygun olmayabilir, bazı durumlarda daha optimize bir performans için doğrudan veri kaynağına erişmek gerekebilir.
Repository Design Pattern C# Örneği
Product isimli entity‘miz için bir repository oluşturmak istediğimizi farz edelim, ilk olarak IProductRepository isimli bir interface tanımlayalım. Bu interface’in içerisinde repository’de bulunmasını istediğimiz işlemleri tanımlayacağız.
public interface IProductRepository
{
Product GetById(int id);
IEnumerable<Product> GetAll();
void Add(Product product);
void Update(Product product);
void Delete(int id);
}
Daha sonrasında bu interface’i veri erişimini gerçekleştireceğimiz ProductRepository isimli sınıfa uyguluyoruz.
public class ProductRepository : IProductRepository
{
private readonly DbContext _dbContext;
public ProductRepository(DbContext dbContext)
{
_dbContext = dbContext;
}
public Product GetById(int id)
{
return _dbContext.Products.Find(id);
}
public IEnumerable<Product> GetAll()
{
return _dbContext.Products.ToList();
}
public void Add(Product product)
{
_dbContext.Products.Add(product);
_dbContext.SaveChanges();
}
public void Update(Product product)
{
var existingProduct = _dbContext.Products.Find(product.Id);
if (existingProduct != null)
{
_dbContext.Entry(existingProduct).CurrentValues.SetValues(product);
_dbContext.SaveChanges();
}
}
public void Delete(int id)
{
var product = _dbContext.Products.Find(id);
if (product != null)
{
_dbContext.Products.Remove(product);
_dbContext.SaveChanges();
}
}
}
Bu şekilde product repository tanımlandı, peki bu repository nasıl kullanılacak? ProductService isimli bir sınıfımız olduğunu varsayalım, uygulamamızın iş mantığının olduğu bir sınıf olduğunu düşünebiliriz.
public class ProductService
{
private readonly IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public void AddNewProduct(Product newProduct)
{
_productRepository.Add(newProduct);
}
public Product GetProductById(int productId)
{
return _productRepository.GetById(productId);
}
public void UpdateProduct(Product updatedProduct)
{
_productRepository.Update(updatedProduct);
}
public void RemoveProduct(int productId)
{
_productRepository.Delete(productId);
}
}
Bu şekilde Product Repository‘sini dependency injection ile sınıfımıza dahil ederek kullanabiliriz.
Bunlara ek olarak ortak olarak bütün repository’lerde bulunmasını istediğimiz işlemleri ortak bir GenericRepository oluşturarak kullanabilir ve bu GenericRepository‘e entity‘leri parametre olarak göndererek her entity için bir repository oluşturma zahmetinden kurtulabiliriz.
GenericRepository‘den de başka bir yazıda bahsedeceğim.