电商平台学习笔记(八)——面向接口编程思想举例分析

Posted on 2016-04-04 21:01  Iltxy  阅读(132)  评论(0)    收藏  举报

  摘要:

  面向接口编程这几个字,听起来真的很熟悉。但是之前体会不是很深,基本上都停留在很低层面上的应用!下面以代码说明:

 1 package cn.ilxy.service.product;
 2 
 3 import java.util.List;
 4 
 5 import cn.ilxy.bean.product.Brand;
 6 import cn.ilxy.enity.Pagination;
 7 import cn.ilxy.query.BrandQuery;
 8 
 9 /**
10   *     品牌 
11   * @author: 张荣
12   * @date: 2016年3月22日
13  */
14 public interface BrandService {
15     //得到品牌分页的相关参数
16     public Pagination getBrandListWithPage(Brand brand);
17     //List集合:查询品牌分页
18     public List<Brand> getBrandList(BrandQuery brandQuery);
19 }
接口定义
 1 package cn.ilxy.service.product;
 2 
 3 import java.util.List;
 4 
 5 import javax.annotation.Resource;
 6 
 7 import org.springframework.stereotype.Service;
 8 import org.springframework.transaction.annotation.Transactional;
 9 
10 import cn.ilxy.bean.product.Brand;
11 import cn.ilxy.dao.product.BrandDao;
12 import cn.ilxy.enity.Pagination;
13 import cn.ilxy.query.BrandQuery;
14 
15 /**
16   * 品牌事务
17   * @author: 张荣
18   * @date: 2016年3月21日
19  */
20 @Service
21 @Transactional
22 public class BrandServiceImpl implements BrandService {
23     @Resource
24     private BrandDao brandDao;
25 
26     @Override
27     @Transactional(readOnly = true)
28     public Pagination getBrandListWithPage(Brand brand) {
29         /*1、起始页号:从1开始索引,则startRow = (pageNo - 1)* pageSize
30          * 2、每页显示记录数
31          * 3、总的记录条数
32          */
33         Pagination pagination = new Pagination(brand.getPageNo(), brand.getPageSize() , brandDao.getBrandCount(brand));
34         //Brand集合
35         pagination.setList(brandDao.getBrandListWithPage(brand));
36         return pagination;
37     }
38 
39     @Override
40     public void addBrand(Brand brand) {
41         brandDao.addBrand(brand);
42     }
43 
44 }
接口实现

  最后在Controller层中注入,并最终完成使用!自己在之前的编码过程中就一直停留在这个层面上!的确没有体会到面向接口编程的精髓,更准确的说,自己对向上转型算是有一定的理解。就像定义泛型一样:List<String> lst = new ArrayList<String>();

  而今天自己看到了一个新的情景下的使用,才对面向接口编程思想有更深的体会和认识!

  情景:

  在做网站时,肯定涉及到Session,比如说从Session域中取值,将值存到Session域中······最好肯定是将这些方法抽象成一个类了。在网站的开发阶段,都是在本机上做测试。这时使用的就是本地Session了,等到项目发布后,使用的肯定就不是本地Session,而是远程Session了。那么问题来了,该怎么设计,才能在项目发布时尽量减少对项目源码的修改?

  分析:

  这两种情况下的Session类中的方法签名肯定是完全一样的了,只是里面的实现细节不一样而已。而这种特点就非常符合接口的使用场景了。本身从接口的定义上来说,接口就是一组方法的抽象。

  源码:

  分析清楚后,代码如下:

 1 package cn.ilxy.web.session;
 2 
 3 import java.io.Serializable;
 4 
 5 import javax.servlet.http.HttpServletRequest;
 6 import javax.servlet.http.HttpServletResponse;
 7 
 8 /**
 9   * 本地session
10   * @author: 张荣
11   * @date: 2016年3月30日
12  */
13 public interface SessionProvider {
14     /**
15      * 往Session里设置值
16      */
17     public void setAttribute(HttpServletRequest request , HttpServletResponse response , String name , Serializable value );
18     
19     /**
20      * 从Session中取值
21      */
22     public Serializable getAttibute(HttpServletRequest request , HttpServletResponse response ,String name);
23     
24     /**
25      * 退出登录
26      */
27     public void loginOut(HttpServletRequest request , HttpServletResponse response );
28     
29     /**
30      * 获取SessionID
31      */
32     public String getSessionId(HttpServletRequest request , HttpServletResponse response);
33 }
Session抽象接口
 1 package cn.ilxy.web.session;
 2 
 3 import java.io.Serializable;
 4 
 5 import javax.servlet.http.HttpServletRequest;
 6 import javax.servlet.http.HttpServletResponse;
 7 import javax.servlet.http.HttpSession;
 8 
 9 /**
10   * 本地Session
11   * @author: 张荣
12   * @date: 2016年3月30日
13  */
14 public class HttpSessionProvider implements SessionProvider{
15 
16     @Override
17     public void setAttribute(HttpServletRequest request,  HttpServletResponse response , String name, Serializable value) {
18         HttpSession session = request.getSession();                //true如果有返回Session,没有就创建一个Cookie  JSESSIONID
19         session.setAttribute(name, value);
20     }
21 
22     @Override
23     public Serializable getAttibute(HttpServletRequest request, HttpServletResponse response ,String name) {
24         HttpSession session = request.getSession(false);
25         if (session != null) {
26             return (Serializable) session.getAttribute(name);
27         }
28         return  null;
29     }
30 
31     @Override
32     public void loginOut(HttpServletRequest request , HttpServletResponse response) {
33         HttpSession session = request.getSession(false);
34         if (session != null) {
35             session.invalidate();
36         }
37         //Cookie: JSESSION
38         
39     }
40 
41     @Override
42     public String getSessionId(HttpServletRequest request , HttpServletResponse response) {
43 //        request.getRequestedSessionId();        //http://localhost:8080/html/sstf.shtml?JESSIONID=ewerq235:获取的是URL的SESSIONID
44         return request.getSession().getId();
45     }
46     
47 }
本地Session实现类
 1 package cn.ilxy.web.session;
 2 
 3 import java.io.Serializable;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 import java.util.UUID;
 7 
 8 import javax.annotation.Resource;
 9 import javax.servlet.http.Cookie;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 
13 import com.danga.MemCached.MemCachedClient;
14 
15 /**
16   * 远程Session,存放在Memcached缓存服务器中
17   * @author: 张荣
18   * @date: 2016年4月3日
19  */
20 public class CacheSessionProvider implements SessionProvider{
21     
22     @Resource
23     private MemCachedClient memCachedClient;
24     
25     private int expiry = 60 * 30;
26     
27     private static final String JSESSIONID="JSESSIONID";
28     
29     public void setExpiry(int expiry) {
30         this.expiry = expiry;
31     }
32 
33     @Override
34     public void setAttribute(HttpServletRequest request, HttpServletResponse response , String name, Serializable value) {
35         Map<String, Serializable> session = new HashMap<String , Serializable>();
36         session.put(name, value);
37         memCachedClient.set(getSessionId(request , response), session , expiry);
38     }
39 
40     @Override
41     public Serializable getAttibute(HttpServletRequest request, HttpServletResponse response , String name) {
42         @SuppressWarnings("unchecked")
43         Map<String, Serializable> session = (Map<String, Serializable>) memCachedClient.get(getSessionId(request, response));
44         if (session != null) {
45             return session.get(name);
46         }
47         return null;
48     }
49 
50     @Override
51     public void loginOut(HttpServletRequest request , HttpServletResponse response) {
52         if (memCachedClient.keyExists(getSessionId(request, response))) {
53             memCachedClient.delete(getSessionId(request, response));
54             /*
55             删除Cookie中的SessionID 
56             Cookie cookie = null;
57             Cookie[] cookies = request.getCookies();
58             for(Cookie c: cookies){
59                 if (c.getName().equals(getSessionId(request, response))) {
60                     cookie = c;
61                     break;
62                 }
63             }
64             if (cookie != null) {
65                 cookie.setMaxAge(0);
66                 cookie.setPath("/");
67             }*/
68         }
69     }
70 
71     @Override
72     public String getSessionId(HttpServletRequest request , HttpServletResponse response) {
73         Cookie[] cookies = request.getCookies();
74         if (cookies != null && cookies.length > 0) {
75             for(Cookie cookie : cookies){
76                 if (JSESSIONID.equals(cookie.getName())) {
77                     return cookie.getValue();
78                 }
79             }
80         }
81         
82         String sessionId = UUID.randomUUID().toString().replaceAll("-", "");
83         Cookie c = new Cookie(JSESSIONID, sessionId);
84         c.setDomain("/");
85         c.setMaxAge(-1);
86         response.addCookie(c);
87         
88         return sessionId;
89     }
90 
91 }
分布式缓存Session实现类

  加载Bean的Spring文件:

  在项目的发布阶段,只需要将上图中class路径写成分布式缓存Session的包+类的路径就可以。而无须再对Java代码人任何修改!而开发人员还认为在服务器上运行的是本地Session实现类中的代码!

  总结:

  面向接口的编程思想的精髓就是一组方法的抽象!通过接口,就可以实现面向对象编程思想的多态特性。就像是USB接口,只要是满足USB接口的标准规格,就可以实现即插即用,无须关心USB接口中的具体实现,也实现了面向对象思想的封装特性。而在本例中,更是明显的体现了这一点,对注入的Session接口而言,完全隐藏了分布式缓存Session的实现细节,或者是分布式缓存Session实现类是透明的!更是结合Spring的IOC容器瞒天过海,实现了“偷天换日”!

  面向接口编程是面向对象编程的升华,巧妙体现了编程之美!

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3