Циркулярная ссылка между сервисами, использующими модель Anemic domain
Я работаю над проектом со сложным бизнесом. Рассмотрим два класса: AccountService и SchoolService
Я использую Unity и распознаватель зависимостей Web API для реализации внедрения зависимостей в конструктор.
Школьная служба использует службу учета в некоторых методах, также служба учета использует школьную службу. Все это требуется в бизнесе проекта. Это вызовет циклическую зависимость, и невозможно переместить методы из одного класса в другой.
Можете ли вы дать какие-либо идеи о том, как решить эту проблему?
Вот пример:
public class SchoolBLC : ISchoolBLC
{
public School GetSchool(int schoolId)
{
...
}
public bool RenewRegistration(int accountId)
{
bool result = true;
IAccountBLC accountBLC = new AccountBLC();
// check some properties related to the account to decide if the account can be renewed
// ex : the account should not be 5 years old
// check the account created date and do renewal
return result;
}
}
public class AccountBLC : IAccountBLC
{
public void ResetAccount(int accountId)
{
ISchoolBLC schoolBLC = new SchoolBLC();
School accountSchool = schoolBLC
// get the school related to the account to send a notification
// and tell the school that the user has reset his account
// reset account and call the school notification service
}
public Account GetAccount(int accountId)
{
...
}
}
Два класса ссылаются друг на друга, это ситуация для 70% BLC в проекте.
2 ответа
Если вам абсолютно необходимо сделать это таким образом, вы можете иметь интерфейс, который выполняет вашу логику IoC, и преобразовать ее в реализацию, которая включает в себя разрешение Unity, например
public interface ITypeResolver
{
T Resolve<T>();
}
Затем вы можете передать этот интерфейс обеим службам в конструкторе и использовать его для "отложенного разрешения" другой службы, прежде чем использовать ее вне конструктора.
Таким образом, когда обе службы инициализируются, они не будут иметь прямой зависимости от другой службы, только ITypeResolver
Я сделаю так, как предлагает @KMoussa, но с некоторыми изменениями:
В проекте используется анемичная модель, поэтому я буду использовать шаблон контекста для отложенной загрузки и создания любого сервиса, и контекст будет передан в качестве параметра конструктору сервиса.
public class SDPContext : ISDPContext
{
private ITypeResolver _typeResolver;
public Account CurrentUser { get; set; }
public IAccountService AccountService
{
get
{
// lazy load the account service
}
}
public ISchoolService SchoolService
{
get
{
// lazy load the schoolservice
}
}
public SDPContext(ITypeResolver typeResolver)
{
this._typeResolver = typeResolver;
}
}
public class ServiceBase
{
public ISDPContext CurrentContext { get; set; }
public ServiceBase(ISDPContext context)
{
this.CurrentContext = context;
}
}
public class AccountService : ServiceBase, IAccountService
{
public AccountService(ISDPContext context) : base(context)
{
}
public bool ResetAccount(int accountId)
{
// use base.Context.SchoolService to access the school business
}
}
public class SchoolService : ServiceBase, ISchoolService
{
public SchoolService(ISDPContext context) : base(context)
{
//this._accountService = accountService;
}
public void RenewRegistration(int accountId)
{
// use the base.Context.Account service to access the account service
}
}