Servlet 接口的耦合与解耦
1. 耦合(Coupling)
- 耦合是指两个或两个以上的体系或两种运动形式间通过相互作用而彼此影响以至联合起来的现象。
- 在软件工程中,对象之间的耦合度就是对象之间的依赖性。对象之间的耦合越高,维护成本越高,因此对象的设计应使类和构件之间的耦合最小。
- 分类:有软硬件之间的耦合,还有软件各模块之间的耦合。耦合性是程序结构中各个模块之间相互关联的度量。它取决于各个模块之间的接口的复杂程度、调用模块的方式以及哪些信息通过接口。
2. 解耦(Decoupling)
- 解耦就是用数学方法将两种运动分离开来处理问题,常用解耦方法就是忽略或简化对所研究问题影响较小的一种运动,只分析主要的运动。
- 在软件工程中,降低耦合度即可以理解为解耦,模块间有依赖关系必然存在耦合,理论上的绝对零耦合是做不到的,但可以通过一些现有的方法将耦合度降至最低。
- 设计的核心思想:尽可能减少代码耦合,如果发现代码耦合,就要采取解耦技术。让数据模型,业务逻辑和视图显示三层之间彼此降低耦合,把关联依赖降到最低,而不至于牵一发而动全身。原则就是A功能的代码不要写在B的功能代码中,如果两者之间需要交互,可以通过接口,通过消息,甚至可以引入框架,但总之就是不要直接交叉写。
- 观察者模式:观察者模式存在的意义就是「解耦」,它使观察者和被观察者的逻辑不再搅在一起,而是彼此独立、互不依赖。比如网易新闻的夜间模式,当用户切换成夜间模式之后,被观察者会通知所有的观察者「设置改变了,大家快蒙上遮罩吧」。QQ消息推送来了之后,既要在通知栏上弹个推送,又要在桌面上标个小红点,也是观察者与被观察者的巧妙配合。
3. 为什么接口能够解耦?
- 因为方法的多态,所以接口的调用者只需要调用接口,具体的业务交给接口的实现者去实现。使用接口,可以避免接口调用方直接参与业务逻辑实现,所以能避免接口调用与业务逻辑实现紧密关联,即解耦。
4. 什么是与 Servlet API 解耦?
- 为了避免与 Servlet API 耦合在一起,方便 Action 做单元测试。
- Struts2 对 HttpServletRequest,HttpSession,和 ServletContext 进行了封装,构造了 3 个 Map 对象来替代这三个对象,在 Action 中可以直接使用 HttpServletRequest,HttpSession,ServletContext 对应的 Map 对象来保存和读取数据。
5. 两种解耦方式
a. 方式一
- 使用 Struts2 提供的工具类中提供的静态方法,得到对用的封装后对象。
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class ContextAction extends ActionSupport {
private static final long serialVersionUID = 1L;
public String test() throws Exception {
System.out.println("ContextAction ****** test()");
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("username", "username_request");
HttpServletResponse response = ServletActionContext.getResponse();
Map sessionMap = ServletActionContext.getContext().getSession();
sessionMap.put("username", "username_session");
ServletContext sc = ServletActionContext.getServletContext();
sc.setAttribute("username", "username_application");
return "attr";
}
}
b. 方式二
- Action 实现 ServletRequestAware,ServletResponseAware,ServletContextAware,SessionAware 四个接口,分别重写对应的 set 方法,达到操作该 4 个封装后对象。
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class Context2Action extends ActionSupport
implements ServletRequestAware, ServletResponseAware, ServletContextAware, SessionAware {
private static final long serialVersionUID = 1L;
HttpServletRequest request;
HttpServletResponse response;
ServletContext context;
Map<String, Object> sessionMap;
public String test() throws Exception {
System.out.println("ContextAction ****** test()");
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("username", "username_request");
HttpServletResponse response = ServletActionContext.getResponse();
Map sessionMap = ServletActionContext.getContext().getSession();
sessionMap.put("username", "username_session");
ServletContext sc = ServletActionContext.getServletContext();
sc.setAttribute("username", "username_application");
return "attr";
}
public void setSession(Map<String, Object> session) {
this.sessionMap = session;
}
public void setServletContext(ServletContext context) {
this.context = context;
}
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
- 其他代码:
struts_context.xml
context/test.jsp
context/success.jsp
context/attr.jsp
6. Struts2 与 Servlet 的耦合有三种实现方案
a. ActionContext
- 在 xwork2.jar 的 com.opensymphony.xwork2.ActionContext 中。
- 这个是最推荐的一种实现。Action 不需要实现接口,只需要引入这个目录即可。
ActionContext.getContext().put("zhangsan","helloworld");
- 只需要一句代码就可以放入 Response 中,页面直接用 EL 表达式 ${requestScope.zhangsan} 获取,取代了标签。
<s:property value="zhangsan"/>
b. servletActionContext
- 在 struts2-core.jar 的 org.apache.struts2.ServletActionContext 中。
- Action 同样也不需要实现接口,只需要引入这个目录即可。
HttpServletResponse response = ServletActionContext.getResponse();
- 实现了 Response对象,然后只需要像往常一样适用。
Cookie cookie = new Cookie("username", this.getUsername());
cookie.setMaxAge(1000);
response.addCookie(cookie);
c. ServletRequestAware,ServletResponseAware 接口实现
- 首先实现接口,然后实现 Request或 Response对象。
import javax.servlet.http.HttpServletRequest;
public class LoginAction extends ActionSupport implements ServletRequestAware {
private static final long serialVersionUID = 3936066275134469754L;
private HttpServletRequest request;
@SuppressWarnings("unchecked")
public String execute() throws Exception {
...
}
@SuppressWarnings("unchecked")
public String hello() throws Exception {
...
request.setAttribute("zhangsan", "helloworld");
...
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
7. Action 类案例
import javax.servlet.http.HttpServletRequest;
public class DemoAction implements Action, ModelDriven<UserInfo>, ServletRequestAware {
private Map<String, Object> map;
private HttpServletRequest request;
private UserInfo user = new UserInfo();
public String execute() throws Exception {
System.out.println("====FirstAction ==============+++execute");
System.out.println("=================" + user);
if (user.getUsername().equals("admin") && user.getPassword().equals("admin")) {
request.getSession().setAttribute("uname", user.getUsername());
return "success";
} else {
return "login";
}
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public UserInfo getUser() {
return user;
}
public void setUser(UserInfo user) {
this.user = user;
}
public UserInfo getModel() {
return null;
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public void setSession(Map<String, Object> map) {
this.map = map;
}
}
原文链接:https://qwert.blog.csdn.net/article/details/105569435