Это правильный способ создания объекта с зависимостями из модели предметной области?
Я пытаюсь избежать использования анемичной модели предметной области, поэтому стараюсь сохранить как можно больше логики в самой модели предметной области. У меня есть метод AddIngredient
, который должен добавить новый KeyedObject
к моему Recipe
Совокупное.
Поскольку предполагается, что сами доменные модели лишены репозиториев, я получаю компонент через класс бизнес-правил:
public class Recipe : AggregateObject
{
public void AddIngredient(int ingId, double quantity)
{
GetIngredientMessage message = new GetIngredientMessage();
message.IngredientId = ingId;
GetIngredient handler = ServiceLocator.Factory.Resolve<GetIngredient>();
Ingredient ingredient = handler.Execute(message);
Ingredients.Add(new OriginalIngredient()
{
Ingredient = ingredient,
Quantity = quantity
});
}
}
Как вы можете видеть, я использую линию линию ServiceLocator.Factory.Resolve<GetIngredient>();
чтобы получить мой GetIngredient
класс бизнес-правил. GetIngredient
простой обработчик команд, который выглядит следующим образом:
public class GetIngredient : ICommandHandler<Ingredient, GetIngredientMessage>
{
private readonly IIngredientRepository _ingredientRepository;
public GetIngredient(IIngredientRepository ingredientRepository)
{
_ingredientRepository = ingredientRepository;
}
}
Я назначаю свой класс фабрики IoC ServiceLocator.Factory
Таким образом, у домена есть возможность использовать свои собственные интерфейсы, не видя конкретную реализацию класса:
ServiceLocator.Factory = new IoCFactory();
Я почти уверен, что я делаю что-то не так, потому что все это выглядит немного странно.
- Кто-нибудь может обнаружить что-то явно не так?
- Есть ли более подходящий способ создания обработчика бизнес-правил, такого как
GetIngredient
без статической ссылки на мой IoC Factory?
1 ответ
Я предлагаю вам ввести еще один слой в дизайн - прикладной уровень. Эта ответственность за уровень будет заключаться в переводе команд (либо явно инкапсулированных в объектах команд, либо передаваемых неявно как int ingId, double quantity
) в вызовы модели предметной области (Recipe.AddIngredient
).
Тем самым вы переместите ответственность за поиск ингредиента по его идентификатору на уровень над доменом, где вы можете безопасно использовать репозитории напрямую, не вводя нежелательную связь. Преобразованное решение будет выглядеть примерно так:
public class ApplicationLayer
{
private readonly IRecipeRepository _recipeRepository;
private readonly IIngredientRepository _ingredientRepository;
/*
* This would be called by IoC container when resolving Application layer class.
* Repositories would be injected by interfacy so there would be no coupling to
* concrete classes.
*/
public ApplicationLayer(IRecipeRepository recipeRepository, IIngredientRepository ingredientRepository)
{
_recipeRepository = recipeRepository;
_ingredientRepository = ingredientRepository;
}
public void AddIngredient(int recipeId, int ingId, double quantity)
{
var recipe = _recipeRepository.FindById(recipeId);
var ingredient = _ingredientRepository.FindById(ingId);
recipe.AddIngredient(ingredient, quantity);
}
}
И теперь упрощенный класс Recipe будет выглядеть примерно так:
public class Recipe : AggregateObject
{
public void AddIngredient(Ingredient ingredient, double quantity)
{
Ingredients.Add(new OriginalIngredient()
{
Ingredient = ingredient,
Quantity = quantity
});
}
}
Надеюсь, это поможет.