Подход MVC веб-приложения Java нуждается в критике - PullRequest
1 голос
/ 12 ноября 2010

У меня есть сервлет, который вызывает общий actions, передающий форму и объект (в зависимости от того, что нужно для действия)

CommitmentServlet.java

CommitmentListDAO clDAO = new CommitmentListDAO();
CommitmentItemForm form = new CommitmentItemForm(clDAO);
CommitmentItem obj = new CommitmentItem();

actionMap.put(null, new ListAction(form);
actionMap.put("list", new ListAction(form);
actionMap.put("view", new ViewAction(form, obj)
actionMap.put("delete", new DeleteAction(form, obj);
actionMap.put("edit", new EditAction(form, obj);

ControllerAction action = (ControllerAction) actionMap.get(request.getParameter("method"));
action.service(request, response);

EditAction.java

public class EditAction implements ControllerAction {
  private Form form;
  private Object obj;

public EditAction(Form form, Object obj) {
    this.form = form;
    this.obj = obj;
}

public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    obj = form.edit(request);

    request.setAttribute("obj", obj);
    request.setAttribute("form", form);

    if (form.isSucces()) {
        RequestDispatcher view = request.getRequestDispatcher(success page);
        view.forward(request, response);
    }
    else {
        RequestDispatcher view = request.getRequestDispatcher(failure page);
        view.forward(request, response);
    }
}
}

Фактическая бизнес-логика находится в объекте form, переданном универсальному действию.
Общие действия позволяют мне быстро получить функциональность CRUD Controller для любых новых объектов. Мне просто нужно кодировать бизнес-логику form, например, здесь

1020 * CommitmentItemForm.java *

public Object edit(HttpServletRequest request) {
    CommitmentItem commitmentItem = null;
    STKUser authenticatedUser = (STKUser) request.getSession().getAttribute("STKUserSession");
    String ownedByBadge = null;
    List deptSupervisorList = null;

    try {
        deptSupervisorList = STKUserDAO.getList(authenticatedUser.getDepartment()); //<--- Static call is it OK??
        commitmentItem = CommitmentListDAO.retreive(request.getParameter("commitment_id"), authenticatedUser);
        ownedByBadge = commitmentItem.getOwned_by();
    }
    catch (DAOException e) {
        setError(FORM_RESULTS, e.getMessage());
    }
    catch (ValidatorException e) {
        // ValidatorExceptions are thrown when the DAO can not find a record
        setError(FORM_RESULTS, e.getMessage());
        LOGGER.log(Level.INFO, e.getMessage(), authenticatedUser);
    }

    if (ownedByBadge != null) {
        if (ownedByBadge.equals(authenticatedUser.getBadge()) || ownedByBadge.equals(authenticatedUser.getAtaBadge())) {
        }
        else {
            setError(FORM_RESULTS, "You are not authorized to edit this data.");
            LOGGER.log(Level.INFO, "Error - You are not authorized to edit this data '" + commitmentItem.getCommitment_id() + "'", authenticatedUser);
        }
    }
    request.setAttribute("deptSupervisorList", deptSupervisorList);  // <--- Is this acceptable to do???
    return commitmentItem;
}

1) Мой подход заключается в установке атрибута запроса и возврате объекта в методе un orditional?
2) Я делаю статический вызов, чтобы получить deptSupervisorList. Это напрашивается на неприятности ??
3) Кажется ли мой сервлет, общее действие, бизнес-форма приемлемым подходом к разработке Java-приложения без использования фреймворка?

EDIT: В чем разница?

Static
deptSupervisorList = STKUserDAO.getList(authenticatedUser.getDepartment()); 

против

non-static
STKUserDAO userDAO = new STKUserDAO();
deptSupervisorList = userDAO.getList(authenticatedUser.getDepartment()); 


public static List getList(String dept) throws DAOException {
   ...
}

1 Ответ

2 голосов
/ 16 ноября 2010

Первые несколько предостережений:

  • Это субъективно
  • Я согласен с SidCool, что ответ заключается в том, чтобы взглянуть на некоторые существующие фреймворки веб-приложений.Во всяком случае, просто чтобы узнать, как они это делают.
  • Я большой поклонник внедрения зависимостей

Чтобы ответить на ваши вопросы:

  • Нелегко передавать данные в атрибутах запроса, потому что: это небезопасно;это немного невидимая сумка вещей - всегда лучше, если вы видите выходные объекты в сигнатуре типа;в какой-то момент вы захотите сохранить две вещи в атрибутах запроса под одним и тем же именем
  • Внедрение зависимостей - это путь в будущее.Выполнение статического вызова плохо, потому что: теперь вы тесно связали два объекта, что затрудняет повторное использование, а также усложняет тестирование
  • Я бы определенно взглянул на некоторые другие фреймворки здесь.Большинство из них, как правило, имеют один сервлет отправки, я думаю, вы в конечном итоге напишите много очень похожих на вид сервлетов.Многие фреймворки также будут использовать рефлексию, чтобы попытаться выполнить преобразование между запросом и POJO как можно раньше и как можно проще.

Другое:

  • Все ваши действия не соответствуют параметрам, т. Е.? Method = [список, просмотр, удаление, редактирование].Часто предпочтительнее использовать маршруты (например, index.html обычно используется для «списка»).

Чтобы ответить на ваши отзывы / вопросы из комментариев:

Выполняетсяна более старой версии Java

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

Что я бы предложил:

  • Попробуйте недавнюю среду Java или даже не Java (например, Ruby onRails), просто чтобы посмотреть, что возможно
  • Когда вы пишете свой собственный единственный фреймворк, просто используйте 1 сервлет и отправьте его на различные «контроллеры».Причина этого в том, что сервлеты не очень хороши для того, чтобы позволить вам собрать все ваше приложение (то, что делает Spring MVC, загружает «приложение» с помощью ContextListener, а затем сервлеты и фильтры ищут «приложение» из ServletContext)

Плотная связь статического

Плотная связь - это когда два объекта нельзя использовать друг без друга, никогда.Вы спросите, почему это плохо?Потому что вы никогда не сможете повторно использовать код для чего-то другого (скажем, если вы решили загрузить некоторые данные из файла, ввели слой кэширования, использовали его в другом проекте и т. Д.).Самое главное, некоторые скажут, что это трудно проверить.Это потому, что вы не можете просто заменить объект, который вы вызываете статически, другим.Интерфейсы обычно используются для разъединения объектов, но на самом деле вы можете сделать это, просто установив объект посредством внедрения зависимостей (что является сложным способом сказать: поместите его в конструктор или как установщик).

OOи быть инженером-строителем

Все хорошо.Некоторые из лучших программистов, которых я знаю, начинали не так.Для меня использование шаблона внедрения зависимостей - отличный способ написать «хороший» код по умолчанию.Примечание: если вы посмотрите на Dependency Injection, вам не нужна инфраструктура для него.Вам просто нужно создать все ваши объекты в одном месте, и все ваши объекты должны получить все свои зависимости либо в конструкторе, либо в установщике.Допускаются не статические методы или синглтоны.

В чем разница

Альтернатива «в чем разница», которая лучше иллюстрирует то, что я имею в виду, будет выглядеть так:

// code in your application builder
// assuming an interface called UserDAO
UserDAO userDAO = new STKUserDAO();
CommitmentItemForm form = new CommitmentItemForm(userDao);


public class CommitmentItemForm {

  private final UserDAO userDao;
  public CommitmentItemForm(UserDAO userDao) { this.userDao = userDao; }

  public Object edit(HttpServletRequest request) {
    ...
    deptSupervisorList = userDao.getList(authenticatedUser.getDepartment());
    ...
  }

}

против

public class CommitmentItemForm {

  public CommitmentItemForm()

  public Object edit(HttpServletRequest request) {
    ...
    deptSupervisorList = STKUserDAO.getList(authenticatedUser.getDepartment());
    ...
  }

}

Статический метод определенно выглядит так, как будто он меньше работает, так почему же он так плох? По сути, это потому, что в статической версии вы никогда не можете искать deptSupervisorList из чего-либо, кроме STKUserDAO. В нестатической версии вы можете предоставить любую реализацию интерфейса UserDAO. Это означает, что вы можете использовать один и тот же код CommitmentItemForm независимо от того:

  • Вы делали это в тесте и создавали пробную версию UserDAO, которая каждый раз возвращала исключение, чтобы вы могли проверить это
  • Вы обнаружили, что вам нужно получить список своих отделов из веб-службы JSON HTTP REST или из файла

Из подписи CommitmentItemForm также сразу видно, что для функционирования ему нужен UserDAO (потому что это требуется в конструкторе).

Это одна из тех маленьких вещей, которые, если вы сделаете это со всем своим кодом, вы обнаружите, что ваш код не только более гибкий, он более тестируемый, более многократно используемый, и части, которые вы внезапно обнаружите, должны изменить в будущем лучше изолированы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...