Пример использования чистой архитектуры для определения разделов домашней страницы ОБНОВЛЕНО

Я экспериментирую с чистой архитектурой Роберта «Дяди Боба» Мартина, чтобы использовать ее в предстоящем проекте. Это веб-приложение на основе Spring MVC.

Одна из особенностей заключается в том, что после входа пользователя в систему на его домашней странице появляются различные разделы в зависимости от типа пользователя.

В моем маленьком прототипе все работает нормально, но я не удовлетворен своим решением. В частности, где я должен определить, с каким типом пользователя я имею дело?

Я также пытаюсь следовать принципу единой ответственности, поэтому я создал абстрактный ViewHomePageUseCase, который имеет дело с общими разделами на всех домашних страницах. У меня также есть ViewUserType1HomePageUseCase и т. д. для определенных типов пользователей, которые расширяют базовый класс.

Хотя в настоящее время в моем Spring @Controller у меня есть что-то вроде этого:

@RequestMapping(value = {"/home"}, method = RequestMethod.GET)
public String getHomePage(Model model) {

    ViewHomePageResponseModel response;
    String userId = "test";

    int userType = this.getUserProfileUseCase.getUserType(userId);
    switch(s) {
    case 1:
        response = useCaseFactory.viewUserType1_HomePageUseCase().getHomePage(userId);
        break;
    case 2:
        response = useCaseFactory.viewUserType2_HomePageUseCase().getHomePage(userId);
        break;
    default:
        response = useCaseFactory.viewSimpleHomePageUseCase().getHomePage(userId);
    }

    HomePageViewModel viewModel = presenter.presentHomePage(response);

    model.addAttribute("viewModel", viewModel);

    return "home";
}

хотя мне не нравится этот контроллер, так как в нем есть бизнес-логика.

В более ранней версии моего прототипа я пытался поместить функцию «определить тип пользователя» в сам вариант использования, а затем делегировать ее правильному варианту использования. Хотя это сработало, мне это тоже не понравилось.

В моей текущей версии мне нравится иметь несколько классов ViewHomePageUseCase через наследование, но я не понимаю, как и где выбрать вариант использования в зависимости от типа пользователя.

Я надеюсь, что я ясно!

Любая помощь приветствуется!

Крис

ОБНОВИТЬ --

В итоге я создал отдельные варианты использования для каждой домашней страницы, а также вариант использования для принятия решения о том, какая домашняя страница нужна. Я также использую factory для создания экземпляра варианта использования. Каждый вариант использования домашней страницы просто получает данные, необходимые для конкретной домашней страницы. Контроллер Spring затем упрощается:

@Controller
public class HomeController {

    private IUseCaseFactory useCaseFactory;

    @Autowired
    public HomeController(IUseCaseFactory useCaseFactory) {
        this.useCaseFactory = useCaseFactory;
    }

    @RequestMapping(value = {"/home"}, method = RequestMethod.GET)
    public String getHomePage(Model model) {

    String userId = "steven"; // User Type 2
    // hardcoded userId's are used in the GetHomePageUseCase class.

    IHomePagePresenter presenter = this.useCaseFactory.getHomePageUseCase().getHomePage(userId);
    HomePageViewModel viewModel = presenter.presentHomePage();

    model.addAttribute("viewModel", viewModel);
    return "home";
    }
}

Мой GetHomePageUseCase, который решает, какая домашняя страница нужна, выглядит примерно так:

public class GetHomePageUseCase implements IViewHomePageUseCase {

    private IUseCaseFactory useCaseFactory;

    public GetHomePageUseCase(IUseCaseFactory useCaseFactory) {
        this.useCaseFactory = useCaseFactory;
    }

    @Override
    public IHomePagePresenter getHomePage(String userId) {
        IHomePagePresenter presenter;

        //temporary
        //TODO - once users are in place, rewrite this function.
        String userRole;
        switch(userId) {
            case "chris":
                userRole = "UserType1";
                break;
            case "steven":
                userRole = "UserType2";
                break;
            default:
                userRole = "Public";
                break;
         }

         switch(userRole) {
         case "UserType1":
             presenter = useCaseFactory.viewUserType1HomePageUseCase().getHomePage(userId);
                break;
         case "UserType2":
            presenter = useCaseFactory.viewUserType2HomePageUseCase().getHomePage(userId);
            break;
        default:
            presenter = useCaseFactory.viewPublicHomePageUseCase().getHomePage(userId);
            break;          
        }

        return presenter;
    }

}

Я все еще не уверен в этом подходе. Хотя он чище, чем первая версия, я им не совсем доволен.

Более общий вопрос: когда у вас есть веб-страница (в данном случае), функции которой зависят от какой-либо роли или разрешений пользователя, как мне учесть эти разрешения пользователя в подходе чистой архитектуры? Например, на другой странице (моя страница просмотра) основные отображаемые данные одинаковы для всех пользователей, но в зависимости от роли/разрешений пользователя пользователь может иметь возможность редактировать, удалять и т. д., в противном случае эти кнопки недоступны. даже отображается. В этом случае (для моей страницы просмотра) у меня есть логические флаги, такие как showEditButton, которые будут установлены с помощью варианта использования, а сам код страницы просмотра просто проверяет флаг, чтобы показать или скрыть кнопку. Это правильный способ сделать это в чистой архитектуре?

Спасибо еще раз!!

Крис


person Chris    schedule 16.01.2020    source источник


Ответы (1)


Домашние страницы — это детали, потому что пользовательский интерфейс — это деталь. Таким образом, варианты использования не должны касаться выбора домашних страниц или разделов.

Глава 22. Варианты использования

Мы также не ожидаем, что на этот уровень повлияют изменения внешних факторов, таких как база данных, пользовательский интерфейс или любая из распространенных платформ. Уровень вариантов использования изолирован от таких проблем.

Мартин, Роберт К. Чистая архитектура: Руководство мастера по структуре и дизайну программного обеспечения (серия Роберта К. Мартина) Pearson Education.

Ваш вариант использования getUserProfileUseCase в порядке, но выбор домашней страницы на основе типа является частью контроллера пользовательского интерфейса.

Я также пытаюсь следовать принципу единой ответственности, поэтому я создал абстрактный ViewHomePageUseCase, который имеет дело с общими разделами на всех домашних страницах.

Даже если ViewHomePageUseCase следует SRP (принцип единой ответственности), ваш контроллер этого не делает. Каждый раз, когда добавляется новый тип пользователя, вы должны изменить оператор switch контроллера. Итак, что бы я сделал, это перенаправить на контроллер, который может обрабатывать тип пользователя.

String redirect = MessageFormat.format("redirect:/home/{0}?userId={1}", userType, userId);
return new ModelAndView(redirect);

Затем вы можете добавить поддержку новых типов пользователей, создав новый класс контроллера, например.

@Controller
@RequestMapping("home")
public class UserType3HomePageController {

    @Autowired
    private UserType3InfoUseCase useCase;

    @GetMapping("/{userType}")
    public ModelAndView getHomePage(@PathVariable int userType, @RequestParam userId) {
        UserType3Info userInfo = useCase.getUserInfo(userId);
        ModelAndView modelAndView = new ModelAndView("userType3Home");
        modelAndView.addObject("userInfo ", userInfo);
        return modelAndView;
    }

}

Тогда у вас также есть разделение задач в контроллерах. Это также имеет смысл, поскольку на разных домашних страницах обычно отображаются разные пользовательские данные. Таким образом, имеет смысл создать представление для каждого типа. В противном случае вы можете получить операторы switch (или if/else) в представлении.

person René Link    schedule 27.01.2020
comment
Извините за поздний ответ, я видел ваш ответ ранее, но был занят здесь работой над другими аспектами этого проекта. - person Chris; 05.02.2020
comment
Я считаю, что решение о том, какую домашнюю страницу отображать, зависит от варианта использования. Тем не менее, похоже, что вы говорите также иметь отдельные URL-адреса и, следовательно, контроллеры для каждого типа домашней страницы пользователя, что возможно. Я как бы надеялся, что не придется так сильно разделять вещи, но опять же, это будет лучше соответствовать SRP. В нашем случае вероятность добавления новых типов пользователей невелика. Я обновлю исходный вопрос выше тем, что я в итоге сделал. - person Chris; 05.02.2020