代码之家  ›  专栏  ›  技术社区  ›  jeff

如何重构此项以减少所需的Java类的数量?

  •  1
  • jeff  · 技术社区  · 14 年前

    我有以下两个类,我开始看到一个模式,即使是我的小Java背景正在尖叫着修复。每一个新对象都需要一组操作,并且类的数量可能会失控。如何将此重构为泛型 DeleteAction 班级?

    我知道一些答案将是使用Hibernate、JPA或某些框架,但目前我不能使用这些工具中的任何一个。哦,我们的服务器只有JDK 1.4(不要问!)谢谢。

    public class DeleteCommitmentAction implements ControllerAction {
    
      public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
    
        CommitmentListDAO clDAO = new CommitmentListDAO();
        CommitmentItemForm ciForm = new CommitmentItemForm(clDAO);
        CommitmentItem commitmentItem = ciForm.deleteCommitmentItem(request);
    
        RequestDispatcher view = request.getRequestDispatcher("views/commitmentView_v.jsp");
        view.forward(request, response);
      }
    }
    

    .

    public class DeleteProgramAction implements ControllerAction {
    
      public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
    
        ProgramDAO prgDAO = new ProgramDAO();
        ProgramForm prgForm = new ProgramForm(prgDAO); 
        ProgramForm prg = prgForm.deleteProgram(request);
    
        RequestDispatcher view = request.getRequestDispatcher("views/programView_v.jsp");
        view.forward(request, response);
      }
    }
    

    我认为我需要采用的方法是创建接口。从DAO开始,我创建了以下接口。

    public interface GenericDao {
      public void create(Object object, STKUser authenticatedUser) throws DAOException;
      public void retreive(String id, STKUser authenticatedUser) throws DAOException;
      public void update( final Object object, STKUser authenticatedUser) throws DAOException;
      public void delete(String id, STKUser authenticatedUser) throws DAOException;
    }
    

    然后在我的DeleteAction类中我尝试了这个

    GenericDao gDAO = new GenericDao();
    

    但是Eclipse声明“不能实例化类型genericDAO”,所以现在我迷路了。

    更新:根据P_)ter t_¶r_¶k的答案,我有:

    这是用于处理承诺项操作的servlet:

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String schema = General_IO.getSchemaPath("TPQOT_463_COMMITMENT", request.getServerName());
        CommitmentListDAO clDAO = new CommitmentListDAO();
        CommitmentItemForm ciForm = new CommitmentItemForm(clDAO);
        CommitmentItem commitmentItem = new CommitmentItem();
    
        // I think this is the Application Controller Strategy
        actionMap.put(null, new ListCommitmentsAction());
        actionMap.put("list", new ListCommitmentsAction());
        actionMap.put("view", new ViewCommitmentItemAction(schema));
        //actionMap.put("delete", new DeleteCommitmentAction(schema));
        // Change to the Generic DeleteAction and pass in the parameters
        actionMap.put("delete", new DeleteAction(ciForm, commitmentItem, schema,  "views/commitmentDeleteConfirm_v.jsp",  "views/commitmentView_v.jsp" ));
        // When happy with this approach, change other actions to the Generic Versions.
    
    
        actionMap.put("sqlConfirmDelete", new DeleteCommitmentConfirmAction());
        actionMap.put("edit", new EditCommitmentItemAction(schema));
        actionMap.put("sqlUpdate", new UpdateCommitmentItemAction1(schema));
        actionMap.put("new", new NewCommitmentFormAction(schema));
        actionMap.put("sqlInsert", new InsertCommitmentItemAction1(schema));
    
        String op = request.getParameter("method");
        ControllerAction action = (ControllerAction) actionMap.get(op);
    
        if (action != null) {
            action.service(request, response);
        } else {
            String url = "views/errorMessage_v.jsp";
            String errMessage = "Operation '" + op + "' not a valid for in '" + request.getServletPath() + "' !!";
            request.setAttribute("message", errMessage);
            request.getRequestDispatcher(url).forward(request, response);
        }
    }
    

    下面是一般的删除操作:

    public class DeleteAction implements ControllerAction {
    
      private Form form;
      private Object obj;
      private String schema = null;
      private String xPage;
      private String yPage;
    
      public DeleteAction(Form form, Object item, String schema, String yPage, String xPage) {
        this.form = form;
        this.item = item;  //passed in javabean??
        this.schema = schema;
        this.xPage = xPage;
        this.yPage = yPage;
      }
    
      public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        item = form.delete(request);
    
        /* Database schema is described in xml files.
        Hash maps of field names, sizes, and titles; foreign key names, titles, 
        lookup tables; and primary keys information are used to dynamically 
        build HTML forms in the views.
        */      
        HashMap test = ReadTableSchema.returnSchema(schema);
        HashMap hshFields = (HashMap) test.get("hshFields");
        HashMap hshForeignKeys = (HashMap) test.get("hshForeignKeys");
        HashMap hshPrimaryKeys = (HashMap) test.get("hshPrimaryKeys");
    
        request.setAttribute("hshFields", hshFields);
        request.setAttribute("hshPrimaryKeys", hshPrimaryKeys);
        request.setAttribute("hshForeignKeys", hshForeignKeys);
    
        request.setAttribute("item", item);
        request.setAttribute("form", form);
        request.setAttribute("pageName", "Delete");
    
        //Check for deletion authorization if successful forward to the confirmation page
        if (form.isSucces()) {
          request.setAttribute("message", "Please confirm permanent deletion of the data below.");
          RequestDispatcher view = request.getRequestDispatcher(yPage);
          view.forward(request, response);
        } else {
          // Not authorized to delete the data so just re-display
          RequestDispatcher view = request.getRequestDispatcher(xPage);
          view.forward(request, response);
        }
      }
    }
    

    然后这里是所有表单都将使用的接口(现在只用于删除)。

    public interface CRUD {
        public Object delete(HttpServletRequest request);
    }
    
    5 回复  |  直到 14 年前
        1
  •  3
  •   Péter Török    14 年前

    你不能实例化一个接口,你需要一个具体的子类。但是,创建具体的子类只会增加类的数量,这是您试图避免的。最好是 使用组合而不是继承 .

    也就是说,如果您设法为表单创建一个公共接口,并隐藏操作 deleteCommitmentItem , deleteProgram 等。在一个方法之后,您可以使用所需的表单(或提供此表单的工厂)参数化您的操作实例,例如:

    public class GenericAction implements ControllerAction {
      private Form form;
      private String page;
    
      GenericAction(Form form, String page) {
        this.form = form;
        this.page = page;
      }
    
      public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
    
        Item item = form.performDelete(request);
    
        RequestDispatcher view = request.getRequestDispatcher(page);
        view.forward(request, response);
      }
    }
    
    ...
    CommitmentListDAO clDAO = new CommitmentListDAO();
    CommitmentItemForm ciForm = new CommitmentItemForm(clDAO);
    GenericAction deleteCommitmentAction = new GenericAction(ciForm, "views/commitmentView_v.jsp");
    
    ProgramDAO prgDAO = new ProgramDAO();
    ProgramForm prgForm = new ProgramForm(prgDAO); 
    GenericAction deleteProgramAction = new GenericAction(prgForm, "views/programView_v.jsp");
    

    因此,对于新类型的操作,您不需要新的类,只需实例化 GenericAction 参数不同。

        2
  •  1
  •   Kirk Woll    14 年前

    很明显,通过您的命名,您已经实现了DAO对象(CommissionListDAO、ProgramDAO)。您应该(可能)修改这些类来实现新的接口。然后您的问题就变成了,您如何知道在执行常规删除操作时要实例化哪个DAO。应该直接将DAO传递到您的操作中,或者必须向您的操作提供一些关于如何实例化它(类或工厂)的其他信息。

        3
  •  1
  •   Kirk Woll    14 年前

    GenericDAO 是接口,不能直接实例化。我不太懂Java,但是每个OOP语言都是一样的。因此,您需要做的是创建接口的具体实现(作为类),然后将其实例化。类似这样的事情(对C代码感到抱歉,但你明白了这一点):

    public interface IGenericDAO {
        void create(...);
    }
    

    执行情况:

    public class GenericDAO implements IGenericDAO {
    
        public void create(...) {
            /* implementation code */
        }
    }
    

    这有道理吗?

        4
  •  1
  •   Tony Ennis    14 年前

    每个动作一个servlet并不不合理。考虑一下,如果您必须执行一些操作x,那么您需要执行x。编写一个servlet来执行x。这很简单。

    正如您注意到的,这可能会导致许多几乎相同的servlet。这没关系,因为现在您可以使用委托(如PeterTorok建议的)或继承将所有共享和抽象的代码移动到一个地方。哪个更好?两者都不如。如果你适当地使用其中一种或两种方法,你就是胜利之路的90%。

    我更喜欢一个主servlet,所有其他servlet都继承它。这允许我将每个服务调用包装在基本控制器类中一致的适当事务中。子类永远不用担心。这段代码显示了它的要点。

    public class BaseControllerAction implements ControllerAction {
    
      public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        Connection conn = null;
        try {
            conn = getAConnection();
            log.info("+++ top of "+getClass().getName());
            conn.getTranaction().begin();
    
            String dest = go(request, response, conn);
    
            conn.getTransaction().commit();
            RequestDispatcher view = request.getRequestDispatcher(dest);
            view.forward(request, response);
    
        } catch (Exception e) {
            conn.getTransaction().rollback();
        } finally {
            conn.close();
            log.info("--- Bottom of "+getClass().getName());
        }
    
    
      protected abstract String go(HttpServletRequest request, HttpServletResponse response, Transaction transaction) throws ServletException;
    
    }
    

    现在您可以实现servlet:

    public class DeleteCommitmentAction extends BaseControllerAction {
      protected String go(HttpServletRequest request, HttpServletResponse response, Connection conn) throws ServletException {
    
       // Given what this method is supposed to do, it's very reasonable
       // to refer to models and DAOs related to deleting commitments.
       Long id = new Long(request.getParameter("id"));
       CommitmentDAO.delete(conn, id);
       return "views/commitmentView_v.jsp";
      }
    }
    

    所以现在您的servlet不必担心事务或者打开和关闭连接。他们只需要担心具体任务的细节。显然,我不知道你的系统,所以我不能给出详细的建议,但这是我最近做了两个大小合适的应用程序。它们每个大约有30个servlet。但是servlet通常大约有15行长。最后我得到了一个实用程序类,它实现了所有servlet所需的各种任务。也许是可怜人的代表团。

        5
  •  0
  •   nanda    14 年前

    无法实例化接口。相反,您应该创建一个实现接口的具体类并实例化这个类。