Hvis jeg  skal hente data fra en database i forbindelse med en ordre, så kan jeg i nogle tilfælde have brug for at hente ordren med ordrelinjer, og i nogle tilfælde kan jeg have brug for kun at hente ordren selv.
I stedet for at hardcode dette i forretningslaget eller i repository, kan jeg lægge det ud for sig selv.
Bemærk venligst at dette er mit forsøg på at forstå en metode, det er ikke “production ready”
Det gør jeg ved først at definerer et interface:
public interface IFetchingStrategy<T> where T : IEntity
{
</span><span style="background: #f9f4f2; color: blue">void </span><span style="background: #f9f4f2">Fetch();
}
Dette interface tager så en IEntity, som er rollen.
Rollen kan være IOrder (hent kun ordren) eller IOrderCalculator(Hent også ordrelinjer) eller IOrderInfo(Hent ordren i readonly tilstand)
public interface IOrder : IEntity
{
}
public interface IOrderCalculator : IEntity
{
Money CalculateCost();
}
public interface IOrderInfo : IEntity
{
}
Nede i mit repository spørger jeg min DI container om en FetchingStrategy
class Repository<T> where T : IEntity
{
public static T FindOne(int id)
{
IFetchingStrategy<T> fetchingStrategy = ResolveType.Of<IFetchingStrategy<T>>();
fetchingStrategy.Fetch();
return default(T);
}
}
Alt efter typen af T, får jeg en forskellig fetching strategy:
public class OrderService
{
public virtual Money CalculateCostForOrder(int orderId)
{
IOrderCalculator order = Repository<IOrderCalculator>.FindOne(orderId);
return new Money();
}
public virtual void DisplayOrder(int orderId)
{
IOrderInfo order = Repository<IOrderInfo>.FindOne(orderId);
}
public void LoadOrder(int orderId)
{
IOrder order = Repository<IOrder>.FindOne(orderId);
}
}
Disse fetching strategier har jeg lagt ud for sig, så de kan ændres flydende (Open / Closed principle)
public class OrderCalculatorFetchingStrategy : IFetchingStrategy<IOrderCalculator>
{
public void Fetch()
{
Console.WriteLine("Fetch the whole bunch - do eager loading");
}
}
public class OrderFetchingStrategy : IFetchingStrategy<IOrder>
{
public void Fetch()
{
Console.WriteLine("Fetch only the order");
}
}
public class OrderInfoFetchingStrategy : IFetchingStrategy<IOrderInfo>
{
public void Fetch()
{
Console.WriteLine("Fetch in read-only mode");
}
}
Her konfigurerer jeg min DI Container:
IWindsorContainer container = new WindsorContainer();
container.AddComponent("OrderCalculatorFetchingStrategy",
typeof(IFetchingStrategy<IOrderCalculator>),
typeof(OrderCalculatorFetchingStrategy));
container.AddComponent("OrderFetchingStrategy",
typeof(IFetchingStrategy<IOrder>),
typeof(OrderFetchingStrategy));
container.AddComponent("OrderInfoFetchingStrategy",
typeof(IFetchingStrategy<IOrderInfo>),
typeof(OrderInfoFetchingStrategy));
ResolveType.Initialize(container);
Kort sagt kan man vel sige at det er en implementation af Strategypattern, hvor man bruger sin DI container til at hente strategien på runtime.
Jeg vil gerne henvise til Udi Dahans blogposts om emnet:
Fetching Stratey Design
Better Domain Driven Design implementation
Ayende har også en god blogpost om emnet:
Adaptive Domain models with Rhino Commons