[英]How do I refactor this to reduce the number of java classes needed?
我有以下兩個類,並且我開始看到一種模式,即使我的Java背景很少,也要求進行修復。 每個新的Object都需要一組Action,並且類的數量可能會增加。 如何將其重構為通用DeleteAction
類?
我知道一些答案將使用Hibernate或JPA或某些Framework,但目前我無法使用任何這些工具。 哦,我們的服務器只有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éterTö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);
}
}
這是通用DeleteAction:
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);
}
您無法實例化接口,為此需要一個具體的子類。 但是,創建具體的子類只會增加類的數量,而您試圖避免這種情況。 最好使用組合而不是繼承 。
也就是說,如果您設法為表單創建一個通用接口,並將動作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
。
GenericDAO
是一個接口,無法直接實例化。 我不太了解Java,但是每種OOP語言都差不多。 因此,您需要做的是創建接口的具體實現(作為類),然后實例化該接口。 像這樣(對不起C#代碼,但您知道了):
public interface IGenericDAO {
void create(...);
}
和實現:
public class GenericDAO implements IGenericDAO {
public void create(...) {
/* implementation code */
}
}
那有意義嗎?
通過命名很明顯,您已經實現了DAO對象(CommitmentListDAO,ProgramDAO)。 您應該(可能)修改這些類以實現您的新接口。 然后您的問題就變成了,當您處於常規刪除操作中時,如何知道要實例化哪個DAO。 應該直接將DAO傳遞到您的操作中,或者必須將有關如何實例化它的其他信息(類或工廠)提供給您的操作。
每個動作一個servlet並非沒有道理。 考慮一下,如果您必須執行一些操作X,那么您就需要執行X。編寫一個servlet來執行X。就這么簡單。
正如您所注意到的,這可能會導致很多幾乎相同的servlet。 沒關系,因為現在您可以使用委托(如Peter Torok推薦的那樣)或繼承將所有共享和抽象的代碼移到一個位置。 哪個更好? 哪一個總比沒有好。 如果您適當地使用一種或兩種,那么您將有90%的勝利之道。
我更喜歡其他所有繼承的主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所需的各種任務。 也許是窮人的代表團。
接口無法實例化。 相反,您應該創建一個實現該接口的具體類並實例化該類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.