IMO Repository
अमूर्त और अमूर्त दोनों का UnitOfWork
किसी भी सार्थक विकास में बहुत मूल्यवान स्थान है। लोग कार्यान्वयन विवरणों के बारे में बहस करेंगे, लेकिन जिस तरह एक बिल्ली को त्वचा देने के कई तरीके हैं, उसी तरह एक अमूर्त को लागू करने के कई तरीके हैं।
आपका प्रश्न विशेष रूप से उपयोग करने या नहीं करने के लिए है और क्यों।
जैसा कि आपको कोई संदेह नहीं है कि आपको पहले से ही इन दोनों पैटर्नों को एंटिटी फ्रेमवर्क में बनाया गया है, DbContext
है UnitOfWork
और DbSet
है Repository
। आपको आमतौर पर इकाई परीक्षण UnitOfWork
या Repository
खुद की आवश्यकता नहीं है क्योंकि वे बस आपकी कक्षाओं और अंतर्निहित डेटा एक्सेस कार्यान्वयन के बीच सुविधा प्रदान कर रहे हैं। यूनिट को आपकी सेवाओं के तर्क का परीक्षण करते समय, आपको बार-बार खुद को ऐसा करने की आवश्यकता होगी, जो इन दो अमूर्तों का मजाक उड़ाता है।
आप परीक्षण कर रहे तर्क और परीक्षण किए जा रहे तर्क के बीच कोड निर्भरता की परतों (जो आप को नियंत्रित नहीं करते हैं) जोड़कर बाहरी पुस्तकालयों के साथ नकली या जो भी कर सकते हैं, नकली कर सकते हैं ।
तो एक मामूली बात यह है कि अपने यूनिट परीक्षण का मजाक उड़ाते समय आपके पास खुद के लिए अमूर्तता है UnitOfWork
और Repository
आपको अधिकतम नियंत्रण और लचीलापन देता है।
सभी बहुत अच्छी तरह से, लेकिन मेरे लिए, इन अमूर्तों की वास्तविक शक्ति यह है कि वे एस्पेक्ट ओरिएंटेड प्रोग्रामिंग तकनीकों को लागू करने और एसओएलआईडी सिद्धांतों का पालन करने का एक सरल तरीका प्रदान करते हैं ।
तो आप अपने IRepository
:
public interface IRepository<T>
where T : class
{
T Add(T entity);
void Delete(T entity);
IQueryable<T> AsQueryable();
}
और इसका कार्यान्वयन:
public class Repository<T> : IRepository<T>
where T : class
{
private readonly IDbSet<T> _dbSet;
public Repository(PPContext context)
{
_dbSet = context.Set<T>();
}
public T Add(T entity)
{
return _dbSet.Add(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
public IQueryable<T> AsQueryable()
{
return _dbSet.AsQueryable();
}
}
साधारण से बाहर कुछ भी नहीं है, लेकिन अब हम एक लॉगिंग डेकोरेटर के साथ कुछ लॉगिंग - आसान जोड़ना चाहते हैं ।
public class RepositoryLoggerDecorator<T> : IRepository<T>
where T : class
{
Logger logger = LogManager.GetCurrentClassLogger();
private readonly IRepository<T> _decorated;
public RepositoryLoggerDecorator(IRepository<T> decorated)
{
_decorated = decorated;
}
public T Add(T entity)
{
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString() );
T added = _decorated.Add(entity);
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
return added;
}
public void Delete(T entity)
{
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
_decorated.Delete(entity);
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
}
public IQueryable<T> AsQueryable()
{
return _decorated.AsQueryable();
}
}
सब किया और हमारे मौजूदा कोड में कोई बदलाव नहीं किया । कई अन्य क्रॉस कटिंग चिंताएं हैं जिन्हें हम जोड़ सकते हैं, जैसे कि अपवाद हैंडलिंग, डेटा कैशिंग, डेटा सत्यापन या जो कुछ भी और हमारे पूरे डिजाइन और निर्माण की प्रक्रिया में हमारे पास सबसे मूल्यवान चीज है जो हमें किसी भी मौजूदा कोड को बदलने के बिना सरल सुविधाओं को जोड़ने में सक्षम बनाती है। हमारा IRepository
अमूर्त है ।
अब, कई बार मैंने स्टैकऑवरफ्लो पर यह प्रश्न देखा है - "आप बहु किरायेदार वातावरण में एंटिटी फ्रेमवर्क कैसे बनाते हैं?"
https://stackoverflow.com/search?q=%5Bentity-framework%5D+multi+tenant
यदि आपके पास Repository
अमूर्तता है, तो उत्तर है "यह एक डेकोरेटर जोड़ना आसान है"
public class RepositoryTennantFilterDecorator<T> : IRepository<T>
where T : class
{
//public for Unit Test example
public readonly IRepository<T> _decorated;
public RepositoryTennantFilterDecorator(IRepository<T> decorated)
{
_decorated = decorated;
}
public T Add(T entity)
{
return _decorated.Add(entity);
}
public void Delete(T entity)
{
_decorated.Delete(entity);
}
public IQueryable<T> AsQueryable()
{
return _decorated.AsQueryable().Where(o => true);
}
}
IMO आपको हमेशा किसी भी 3 पार्टी घटक पर एक साधारण अमूर्त जगह देनी चाहिए जो एक से अधिक स्थानों पर संदर्भित होगी। इस दृष्टिकोण से एक ORM सही उम्मीदवार है क्योंकि यह हमारे कोड के बहुत में संदर्भित है।
इसका जवाब जो आम तौर पर दिमाग में आता है जब कोई कहता है कि "मुझे Repository
इस या उस 3 पार्टी लाइब्रेरी पर अमूर्तता (जैसे ) क्यों होनी चाहिए " क्या आप क्यों नहीं? "
पीएस डेकोरेटर्स आईओसी कंटेनर का उपयोग करके लागू करने के लिए बेहद सरल हैं, जैसे कि सिम्पलइन्जेक्टर ।
[TestFixture]
public class IRepositoryTesting
{
[Test]
public void IRepository_ContainerRegisteredWithTwoDecorators_ReturnsDecoratedRepository()
{
Container container = new Container();
container.RegisterLifetimeScope<PPContext>();
container.RegisterOpenGeneric(
typeof(IRepository<>),
typeof(Repository<>));
container.RegisterDecorator(
typeof(IRepository<>),
typeof(RepositoryLoggerDecorator<>));
container.RegisterDecorator(
typeof(IRepository<>),
typeof(RepositoryTennantFilterDecorator<>));
container.Verify();
using (container.BeginLifetimeScope())
{
var result = container.GetInstance<IRepository<Image>>();
Assert.That(
result,
Is.InstanceOf(typeof(RepositoryTennantFilterDecorator<Image>)));
Assert.That(
(result as RepositoryTennantFilterDecorator<Image>)._decorated,
Is.InstanceOf(typeof(RepositoryLoggerDecorator<Image>)));
}
}
}