Веб-приложения Design Patterns [закрыто]

357
задан klutt 4 November 2017 в 04:29
поделиться

3 ответа

Немного приличное веб-приложение состоит из смеси шаблонов проектирования. Упомяну только самые важные.


Шаблон Model View Controller

Основной (архитектурный) шаблон проектирования, который вы хотите использовать, - это шаблон Model-View-Controller . Контроллер должен быть представлен сервлетом, который (in) напрямую создает / использует определенные Модель и View на основе запроса. Модель должна быть представлена ​​классами Javabean.Это часто дополнительно разделяется в бизнес-модели , которая содержит действия (поведение), и модели данных , которая содержит данные (информацию). Представление должно быть представлено файлами JSP, которые имеют прямой доступ к ( Data ) модели от EL (язык выражений).

Кроме того, существуют варианты, основанные на том, как обрабатываются действия и события. Наиболее популярными из них являются:

  • MVC на основе запроса (действия) : это самый простой в реализации. Модель ( Business ) работает напрямую с объектами HttpServletRequest и HttpServletResponse . Вы должны собрать, преобразовать и проверить параметры запроса (в основном) самостоятельно. Представление может быть представлено обычным HTML / CSS / JS и не поддерживает состояние между запросами. Вот как среди прочих работает Spring MVC , Struts и Stripes .

  • MVC на основе компонентов : это сложнее реализовать. Но в итоге вы получаете более простую модель и представление, в котором весь «сырой» API сервлетов полностью абстрагируется. Вам не нужно самостоятельно собирать, конвертировать и проверять параметры запроса. Контроллер выполняет эту задачу и устанавливает собранные, преобразованные и проверенные параметры запроса в модели . Все, что вам нужно сделать, это определить методы действий, которые работают непосредственно со свойствами модели.Представление представлено «компонентами» в виде библиотеки тегов JSP или элементов XML, которые, в свою очередь, генерируют HTML / CSS / JS. Состояние представления для последующих запросов сохраняется в сеансе. Это особенно полезно для событий преобразования, проверки и изменения значений на стороне сервера. Вот как среди прочих JSF , Wicket и Play! работает.

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

В приведенном ниже подробном объяснении я ограничусь MVC на основе запросов, поскольку это проще реализовать.


Шаблон фронтального контроллера ( Шаблон посредника )

Во-первых, часть Контроллер должна реализовывать шаблон фронтального контроллера (который является специализированным разновидность паттерна посредника ). Он должен состоять только из одного сервлета, который обеспечивает централизованную точку входа для всех запросов. Он должен создать Модель на основе информации, доступной по запросу, такой как pathinfo или servletpath, метод и / или определенные параметры.Бизнес-модель называется Action в приведенном ниже примере HttpServlet .

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        Action action = ActionFactory.getAction(request);
        String view = action.execute(request, response);

        if (view.equals(request.getPathInfo().substring(1)) {
            request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
        }
        else {
            response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern).
        }
    }
    catch (Exception e) {
        throw new ServletException("Executing action failed.", e);
    }
}

Выполнение действия должно возвращать некоторый идентификатор для определения местоположения представления. Проще всего было бы использовать его как имя файла JSP. Сопоставьте этот сервлет с определенным шаблоном URL в web.xml , например / pages / * , *.выполните или даже просто *. html .

В случае шаблонов префиксов, например / pages / * , вы можете затем вызывать URL-адреса вида http://example.com/pages/register , http : //example.com/pages/login и т. д. и предоставить /WEB-INF/register.jsp , /WEB-INF/login.jsp с соответствующим GET и действия POST. Части регистр , логин и т. Д. Затем доступны через request.getPathInfo () , как в примере выше.

Когда вы используете шаблоны суффиксов, такие как *. Do , *. Html и т. Д., Тогда вы можете вызывать URL-адреса вида http: // example. com / register.do , http://example.com/login.do и т. д., и вам следует изменить примеры кода в этом ответе (также ActionFactory ) на вместо этого извлеките части регистра и входа в систему с помощью request.getServletPath () .


Шаблон стратегии

Действие должно соответствовать шаблону стратегии . Он должен быть определен как абстрактный / интерфейсный тип, который должен выполнять работу на основе переданных аргументов абстрактного метода (в этом отличие от командного шаблона , в котором тип abstract / interface должен выполнять работу на основе аргументов, переданных во время создания реализации).

public interface Action {
    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

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

Вот пример LoginAction , которое (как следует из названия) выполняет вход пользователя в систему. Сам Пользователь , в свою очередь, является моделью данных . Представление знает о присутствии пользователя .

public class LoginAction implements Action {

    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        User user = userDAO.find(username, password);

        if (user != null) {
            request.getSession().setAttribute("user", user); // Login user.
            return "home"; // Redirect to home page.
        }
        else {
            request.setAttribute("error", "Unknown username/password. Please retry."); // Store error message in request scope.
            return "login"; // Go back to redisplay login form with error.
        }
    }

}

Шаблон заводского метода

ActionFactory должен следовать шаблону Заводского метода . По сути, он должен предоставлять метод создания, который возвращает конкретную реализацию абстрактного / интерфейсного типа. В этом случае он должен вернуть реализацию интерфейса Action на основе информации, предоставленной запросом. Например, метод и pathinfo (pathinfo - это часть после контекста и пути сервлета в URL-адресе запроса, за исключением строки запроса).

public static Action getAction(HttpServletRequest request) {
    return actions.get(request.getMethod() + request.getPathInfo());
}

Действия , в свою очередь, должны быть некой статической / общесистемной Map , которая содержит все известные действия. Как заполнить эту карту - решать вам. Жесткое кодирование:

actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...

Или настраивается на основе свойств / файла конфигурации XML в пути к классам: (псевдо)

for (Entry entry : configuration) {
    actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}

Или динамически на основе сканирования в пути к классам для классов, реализующих определенный интерфейс и / или аннотацию: (псевдо)

for (ClassFile classFile : classpath) {
    if (classFile.isInstanceOf(Action.class)) {
       actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
    }
}

Не забудьте создать действие «ничего не делать» на случай отсутствия сопоставления. Пусть, например, он сразу вернет запрос .getPathInfo (). substring (1) тогда.


Другие образцы

До сих пор это были важные образцы.

Чтобы продвинуться дальше, вы можете использовать паттерн Facade для создания класса Context , который, в свою очередь, обертывает объекты запроса и ответа и предлагает несколько удобных методов, делегирующих запрос и объекты ответа и вместо этого передайте его в качестве аргумента в метод Action # execute () . Это добавляет дополнительный абстрактный слой, чтобы скрыть необработанный API сервлетов. В результате вы должны получить ноль import javax.servlet. * объявлений в каждой реализации Action . В терминах JSF это то, что делают классы FacesContext и ExternalContext . Вы можете найти конкретный пример в ответе .

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

Затем есть Составной шаблон для случая, когда вы хотите создать представление на основе компонентов, которое может быть присоединено к модели и поведение которого зависит от состояния жизненного цикла на основе запроса. В терминах JSF это то, что представляет UIComponent .

Таким образом, вы можете постепенно развиваться в сторону компонентной структуры.


См. Также:

485
ответ дан 23 November 2019 в 00:21
поделиться

В избитом шаблоне MVC сервлет является «C» -контроллером.

Его основная задача - выполнить первоначальную оценку запроса и затем передать обработку на основе начальной оценки конкретному исполнителю. Одна из обязанностей рабочего может заключаться в настройке некоторых bean-компонентов уровня представления и пересылке запроса на страницу JSP для визуализации HTML. Итак, только по этой причине вам необходимо передать объект запроса на уровень сервиса.

Однако я бы не стал писать необработанные классы сервлетов . Работа, которую они делают, очень предсказуема и шаблонна, с чем отлично справляется фреймворк. К счастью, есть много доступных, проверенных временем кандидатов (в алфавитном порядке): Apache Wicket , Java Server Faces , Spring и многие другие.

13
ответ дан 23 November 2019 в 00:21
поделиться

ИМХО, в случае с веб-приложением особой разницы нет, если смотреть на него с точки зрения распределения ответственности. Однако сохраняйте четкость слоя. Храните что-либо исключительно для целей презентации на уровне представления, например элементы управления и код, специфичные для веб-элементов управления. Просто сохраните свои объекты на бизнес-уровне, а все функции (например, добавление, редактирование, удаление) и т. Д. На бизнес-уровне. Однако рендеринг их в браузере для обработки на уровне представления. Для .Net шаблон ASP.NET MVC очень хорош с точки зрения разделения слоев. Посмотрите на шаблон MVC.

5
ответ дан 23 November 2019 в 00:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: