Шаблон стратегии создает зависимость с классом Controller в Asp.net MVC 3.0 - PullRequest
3 голосов
/ 06 сентября 2011

Я работаю с продуктом CRM, который использует ASP.net MVC 3.0, Entity Framework и Windsor для контейнера IOC.

Я ввел сервисы, работающие со слоем репозитория, в контроллер через Windsor.

Однако я реализовал шаблон стратегии для моих ContactController, чтобы облегчить MyProfile, CustomerProfile, CompanyProfile.

Теперь мой класс ContactContext зависит от моего класса ContactController, поэтому я не могу вводить ContactContext с помощью WindsorВ результате я создал экземпляр ContactContext в ContactController.

ContactController реализация класса

 public class ContactController:BaseController
 {
    private ContactContext _contactContext;

    public ContactController(PersonService personService, CompanyService customerService)
    {
        _contactContext = new ContactContext(personService, customerService, this);
    }

    public ActionResult ContactProfile(string profileId, string profileType)
    {
       base.ValidateContactProfileIdAndProfileTypeInfo(profileType, profileId);
       return _contactContext.RenderContactProfile(ProfileType, ProfileId);
    }
  }

ContactContext реализация

public class ContactContext
{
    private Dictionary<ProfileType, IContactStrategy> _strategies =
    new Dictionary<ProfileType, IContactStrategy>();

    private BaseController _controller;

    public ContactContext(PersonService personService, CompanyService companyService, BaseController controller)
    {
        _strategies.Add(ProfileType.MyProfile, new MyProfileStrategy(personService));
        _strategies.Add(ProfileType.CustomerProfile, new PersonStrategy(personService));
        _strategies.Add(ProfileType.CompanyProfile, new CompanyStrategy(companyService));

        _controller = controller;
    }

    public ActionResult RenderProfileInfo(ProfileType profileType, long profileId)
    {
        return _strategies[profileType].GenerateProfileInfoView(profileId, _controller);
    }

    public ActionResult RenderPeopleInfo(ProfileType profileType, long profileId)
    {
        return _strategies[profileType].GeneratePeopleInfoView(profileId, _controller);
    }
 }

Стратегии идут так:

public class PersonStrategy:IContactStrategy
{
    private PersonService _personService;

    public PersonStrategy(PersonService personService)
    {
        _personService = personService;
    }


    #region Implementation of IContactStrategy

    public ActionResult GenerateProfileInfoView(long profileId, BaseController controller)
    {
        //TODO: Load Profile info from service
        PersonDetailsViewModel personDetailsViewModel = new PersonDetailsViewModel();
        personDetailsViewModel.Name = "Robert Martin";

        return controller.RenderPartialView("ProfileInfo", personDetailsViewModel);
    }

    public ActionResult GeneratePeopleInfoView(long profileId, BaseController controller)
    {
        //TODO: Load people from service
        return controller.RenderPartialView("PeopleView", new List<PersonLiteViewModel>());
    }
  }

public class CompanyStrategy : IContactStrategy
{
    private CompanyService _companyService;

    public CompanyStrategy(CompanyService companyService)
    {
        _companyService = companyService;
    }

    #region Implementation of IContactStrategy

    public ActionResult GenerateView(long profileId, BaseController controller)
    {
        throw new NotImplementedException();
    }

    public ActionResult GenerateProfileInfoView(long profileId, BaseController controller)
    {
        throw new NotImplementedException();
    }
 }

Вопрос: Как я могу получитьизбавить от ContactContext зависимость с ContactController?

Ответы [ 2 ]

1 голос
/ 06 сентября 2011

Я думаю, что есть несколько вариантов.

На основании приведенных примеров кода (которые могут быть неполными, поэтому это невозможно), вы можете просто получить ContactContext, чтобы вернуть IContactStrategy к контроллеру и вызовите представление, проходящее в контроллере, поскольку тогда ContactContext не нужно ничего знать о контроллере, он может просто отвечать за настройку и реализацию правильной реализации стратегии.

ОДНАКО:

Есть ли причина для того, чтобы PersonService и CompanyService передавались в контроллер, кроме как для передачи их в конструктор ContactContext?Если нет, то это пахнет для меня.Если вы только передаете что-то, чтобы вы могли создать что-то еще, используя это, то обычно я думаю, что было бы лучше просто передать экземпляр того, что вы создаете.Представьте себе, если в будущем вы добавите другую стратегию, которая нуждается в VoluteerService или подобном.Вам нужно будет добавить это в конструктор контроллера, чтобы потом передать его конструктору ContractContext.

В этом случае я бы сделал что-то вроде создания интерфейса IContactStrategyFactory, который я передамэкземпляр в ContactController.Это может быть сделано windsor, и реализация по умолчанию будет зависеть от PersonService и CustomerService.тогда у меня будет либо

  1. метод, чтобы получить IContractStrategy по имени и вызвать его в контроллере (как было предложено в начале).
  2. есть метод, чтобы получить его, передавая имя, контроллер и контроллер, и заставить фабрику установить контроллер в стратегии и вернуть его.
  3. есть методы, аналогичные тем, которые есть у вас сейчас на ContactContext, но с дополнительным параметром (контроллером).

Номер 1 кажется мне самым простым, и я бы, наверное,пойти с этим.2. это вариант, но мне это не очень нравится, так как необходимость установки контроллера вне конструктора означает, что он может быть забыт.Наличие фабрики означает, что это, вероятно, не будет, но все же ... 3, вероятно, больше всего похоже на то, что у вас есть сейчас, и может быть самым простым.Если вы сохранили имена классов, которые у вас есть, вы можете просто удалить BaseController из конструктора ContactContext и вместо этого добавить его в методы GenerateProfileInfoView и GenerateProfileInfoView, а затем сделать ContactController take ContactContext inконструктор (или интерфейс, извлеченный из этого)

0 голосов
/ 06 сентября 2011

Я реализовал фабрику для создания ContactContext и внедрения его с использованием контейнера

public class ContactController:BaseController
{
 private ContactContext _contactContext;

 public ContactController(ContactContextFactory contactContextFactory)
 {
    _contactContext = contactContextFactory.GetContactContext(this);
 }
}

public class ContactContextFactory
    {
        private PersonService _personService;
        private CompanyService _customerService;

        public ContactContextFactory(PersonService personService, CompanyService companyService)
        {
            _personService = personService;
            _customerService = companyService;
        }

        public ContactContext GetContactContext(BaseController baseController)
        {
            return new ContactContext(_personService, _customerService, baseController);
        }
    }

Есть предложения или улучшения?

...