装饰器模式
应用场景:在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每 次访问中根据需要会去访问不同的数据库。我们以往在 Spring 和 Hibernate 框架中总是配置一个数据 源,因而 SessionFactory 的 DataSource 属性总是指向这个数据源并且恒定不变,所有 DAO 在使用 SessionFactory 的时候都是通过这个数据源访问数据库。但是现在,由于项目的需要,我们的 DAO 在 访问 SessionFactory 的时候都不得不在多个数据源中不断切换,问题就出现了:如何让 SessionFactory 在执行数据持久化的时候,根据客户的需求能够动态切换不同的数据源?我们能不能 在 Spring 的框架下通过少量修改得到解决?是否有什么设计模式可以利用呢? 首先想到在 Spring 的 ApplicationContext 中配置所有的 DataSource。这些 DataSource 可能是各 种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL 等,也可能是不同的数据源:比如 Apache 提 供 的 org.apache.commons.dbcp.BasicDataSource 、 Spring 提 供 的 org.springframework.jndi.JndiObjectFactoryBean 等。然后 SessionFactory 根据客户的每次 请求,将 DataSource 属性设置成不同的数据源,以到达切换数据源的目的。 Spring 中用到的包装器模式在类名上有两种表现:一种是类名中含有 Wrapper,另一种是类名中含有 Decorator。基本上都是动态地给一个对象添加一些额外的职责。
参考博客:https://www.cnblogs.com/jzb-blog/p/6717349.html
实现方式:
public class Member { private String username; private String password; private String mid; private String info; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getMid() { return mid; } public void setMid(String mid) { this.mid = mid; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
public class ResultMsg { private int code; private String msg; private Object data; public ResultMsg(int code, String msg, Object data) { this.code = code; this.msg = msg; this.data = data; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
public interface ISigninService { public ResultMsg regist(String username,String password); /** * 登录的方法 * @param username * @param password * @return */ public ResultMsg login(String username,String password); }
public class SigninService implements ISigninService { public ResultMsg regist(String username,String password){ return new ResultMsg(200,"注册成功",new Member()); } /** * 登录的方法 * @param username * @param password * @return */ public ResultMsg login(String username,String password){ return null; } }
public interface ISigninForThirdService extends ISigninService { public ResultMsg loginForQQ(String openId); public ResultMsg loginForWechat(String openId); public ResultMsg loginForToken(String token); public ResultMsg loginForTelphone(String telphone,String code); public ResultMsg loginForRegist(String username,String password); }
public class SigninForThirdService implements ISigninForThirdService { private ISigninService service; public SigninForThirdService(ISigninService service){ this.service = service; } @Override public ResultMsg regist(String username, String password) { return service.regist(username,password); } @Override public ResultMsg login(String username, String password) { return service.login(username,password); } public ResultMsg loginForQQ(String openId){ //1、openId是全局唯一,我们可以把它当做是一个用户名(加长) //2、密码默认为QQ_EMPTY //3、注册(在原有系统里面创建一个用户) //4、调用原来的登录方法 return loginForRegist(openId,null); } public ResultMsg loginForWechat(String openId){ return null; } public ResultMsg loginForToken(String token){ //通过token拿到用户信息,然后再重新登陆了一次 return null; } public ResultMsg loginForTelphone(String telphone,String code){ return null; } public ResultMsg loginForRegist(String username,String password){ this.regist(username,null); return this.login(username,null); } }
测试类:
public class SigginTest { public static void main(String[] args) { //原来的功能依旧对外开放,依旧保留 //新的功能同样的也可以使用 ISigninForThirdService signinForThirdService = new SigninForThirdService(new SigninService()); signinForThirdService.loginForQQ("xxssdsd"); // Decorator // Wrapper /* ===============================================================------ 装饰器模式 | 适配器模式 -----------------------------------+--------------------------------- 是一种非常特别的适配器模式 | 可以不保留层级关系 -----------------------------------+--------------------------------- 装饰者和被装饰者都要实现同一个接口 | 适配者和被适配者没有必然的层级联系 主要目的是为了扩展,依旧保留OOP关系 | 通常采用代理或者继承形式进行包装 -----------------------------------+---------------------------------- 满足is-a的关系 | 满足has-a -----------------------------------+---------------------------------- 注重的是覆盖、扩展 | 注重兼容、转换 -----------------------------------+---------------------------------- */ } }