适配器模式
适配器模式又叫做变压器模式,它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作,属于结构型模式。
适配器模式应用在项目维护阶段。
应用场景
1.存在已有的功能,内容满足需求但是接口不匹配
2.随着软件的维护,各种功能类似但是接口不相同
实际场景:充电器适配器(将220V交流电适配成手机需要的电压)、读卡器
通用类图
适配器模式一般包含三种角色:
- 目标角色(Target):目标接口
- 源角色(Adaptee):内容满足需求但是接口不匹配
- 适配器(Adapter):将源角色转换为目标角色
适配器模式有三种形式:类适配器、对象适配器、接口适配器。
类适配器
通过继承实现功能。
对象适配器
通过组合实现功能。
接口适配器
应用于目标接口方法过多时,如果直接实现接口类会显得很臃肿,因此将适配器设定为抽象类,并且空实现接口方法,由其子类去实现需要实现的方法。
案例演示
登录相关场景:目前存在一个可以通过用户名和密码完成登录的功能,要求可以通过qq、微信、token、手机号登录。
//用户信息
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 class PassportService {
/**
* 注册方法
* @param username
* @param password
* @return
*/
public ResultMsg regist(String username,String password){
System.out.println(String.format(username + "注册成功"));
return new ResultMsg(200,"注册成功",new Member());
}
/**
* 登录的方法
* @param username
* @param password
* @return
*/
public ResultMsg login(String username,String password){
System.out.println(String.format(username + "----" + password + "登录成功"));
return null;
}
}
//目标角色
public interface IPassportForThird {
ResultMsg loginForQQ(String openId);
ResultMsg loginForWechat(String openId);
ResultMsg loginForToken(String token);
ResultMsg loginForTelphone(String phone, String code);
}
接口适配器实现方式
//抽象适配器
public abstract class PassportForThirdAdapter extends PassportService implements IPassportForThird {
protected ResultMsg loginForRegist(String username,String password){
if(null == password){
password = "THIRD_EMPTY";
}
super.regist(username,password);
return super.login(username,password);
}
@Override
public ResultMsg loginForQQ(String openId) {
return null;
}
@Override
public ResultMsg loginForWechat(String openId) {
return null;
}
@Override
public ResultMsg loginForToken(String token) {
return null;
}
@Override
public ResultMsg loginForTelphone(String phone, String code) {
return null;
}
}
//子类适配器
public class QQPassportForThirdAdapter extends PassportForThirdAdapter {
@Override
public ResultMsg loginForQQ(String openId) {
System.out.println("qq登录");
return loginForRegist(openId,null);
}
}
//子类适配器
public class WeChatPassportForThirdAdapter extends PassportForThirdAdapter {
@Override
public ResultMsg loginForWechat(String openId) {
System.out.println("微信登录");
return loginForRegist(openId,null);
}
}
策略模式实现方式
不同的登陆形式意味着不同的登陆算法,抽象出登录接口。
public interface IStrategy {
/**
* 判断是否属于当前类的登录形式
*
* @param iStrategy: 策略类对象
* @return: boolean
**/
boolean support(Class<? extends IStrategy> iStrategy);
/**
* 实现登录
*
* @param openId: 用户身份标识
* @param iStrategy: 策略类对象 。由于登录接口一致,子类无法判断是否属于自身的登录形式,传入类对象指明由何种类处理
* @return: com.yjf.secondpart.design.pattern.adapter.demo.passport.ResultMsg
**/
ResultMsg commonLogin(String openId,Class<? extends IStrategy> iStrategy);
}
不同的策略类对象都需要用到源角色的方法,因此新增抽象类继承源角色实现策略类。
public abstract class AbstractStrategy extends PassportService implements IStrategy {
protected ResultMsg loginForRegist(String username, String password){
if(null == password){
password = "THIRD_EMPTY";
}
super.regist(username,password);
return super.login(username,password);
}
}
public class LoginForQQStrategy extends AbstractStrategy{
@Override
public boolean support(Class<? extends IStrategy> iStrategy) {
return iStrategy == LoginForQQStrategy.class;
}
@Override
public ResultMsg commonLogin(String openId,Class<? extends IStrategy> iStrategy) {
if(!support(iStrategy)){
System.out.println("调用类型异常");
return null;
}
System.out.println("qq登录");
return super.loginForRegist(openId,null);
}
}
public class LoginForWechatStrategy extends AbstractStrategy{
@Override
public boolean support(Class<? extends IStrategy> iStrategy) {
return iStrategy == LoginForWechatStrategy.class;
}
@Override
public ResultMsg commonLogin(String openId,Class<? extends IStrategy> iStrategy) {
if(!support(iStrategy)){
System.out.println("调用类型异常");
return null;
}
System.out.println("微信登录");
return super.loginForRegist(openId,null);
}
}
//适配器
public class PassportForThirdAdapter implements IPassportForThird {
private IStrategy strategy;
public PassportForThirdAdapter(IStrategy strategy){
this.strategy = strategy;
}
@Override
public ResultMsg loginForQQ(String openId) {
return strategy.commonLogin(openId,LoginForQQStrategy.class);
}
@Override
public ResultMsg loginForWechat(String openId) {
return strategy.commonLogin(openId,LoginForWechatStrategy.class);
}
@Override
public ResultMsg loginForToken(String token) {
return strategy.commonLogin(token,LoginForTokenStrategy.class);
}
@Override
public ResultMsg loginForTelphone(String phone, String code) {
return strategy.commonLogin(phone,LoginForTelStrategy.class);
}
}
//策略工厂
public class StrategyFactory {
public static final String QQ_LOGIN = "QQ";
public static final String WECHAT_LOGIN = "Wechat";
public static final String TEL_LOGIN = "Tel";
public static final String TOKEN_LOGIN = "Token";
public static final String DEFAULT_LOGIN = "DEFAULT";
private static Map<String, IStrategy> map = new HashMap<>();
private StrategyFactory(){
}
static {
map.put(QQ_LOGIN,new LoginForQQStrategy());
map.put(WECHAT_LOGIN,new LoginForWechatStrategy());
map.put(TEL_LOGIN,new LoginForTelStrategy());
map.put(TOKEN_LOGIN,new LoginForTokenStrategy());
}
public static IStrategy getStrategy(String key){
if(!map.containsKey(key)){
return map.get(DEFAULT_LOGIN);
}
return map.get(key);
}
}
桥接模式
桥接模式也称为桥梁模式、接口模式或柄体模式,是将抽象部分与它的具体实现部分分离,使它们都可以独立的变化,属于结构性模式。
此处的抽象并非abstract和interface的概念,实现也不是extends和implements的概念。抽象和实现指的是两种变化的维度,抽象包含实现。
桥接模式的主要目的是通过组合的方式建立类之间的联系,而不是继承。桥接模式的核心在于解耦抽象和实现。
应用场景
1.一个类存在多个独立变化的维度,而这些维度都需要独立的扩展。
2.不希望使用继承,或因为继承导致类的数量剧增。(说明:设想存在以下场景,有大、小、中三种尺寸,有芒果、橘子两种水果,在通过继承创建对象时,要得到六个对象大芒果、小芒果、中芒果、中橘子、大橘子、小橘子就需要创建六个类,想多加一个水果时,又要新增三个类;而如果通过桥接模式,只需要新增水果一个类即可,避免了类暴增)
实际场景:连接两岸的桥(桥为抽象、两岸为实现)、虚拟网络与真实网络的桥接(虚拟为抽象、真实为实现)
通用类图
桥接模式一般包含四种角色:
- 抽象(Abstraction):该类持有实现角色的引用,抽象角色中的方法需要实现角色来实现。
- 修正抽象(RefineAbstraction):抽象角色的实现,对抽象角色的方法进行完善和扩展。
- 实现(Implementor):提供该维度的基本行为,被抽象角色引用
- 具体实现(ConcreteImplementor):Implementor的具体实现
案例演示
发送信息相关场景:发送信息可以通过短信发送,也可以通过邮件发送,发送的信息又因为信息的紧急程度分为紧急和普通,发送的信息也可以即时发送或者定时发送,使用桥接模式设计相关场景。
如上所述,发送信息存在三个维度,信息发送途径,信息紧急程度,信息发送时间。
信息发送途径为抽象,其他两个维度为实现。
//信息紧急程度 实现
public interface IEmergency {
String emergency();
}
//具体实现
public class Normal implements IEmergency {
@Override
public String emergency() {
return "-----这是普通的消息";
}
}
//具体实现
public class Urgency implements IEmergency {
@Override
public String emergency() {
return "-----这是紧急的消息";
}
}
//信息发送时间 实现
public interface ISendTime {
String sendTime();
}
//具体实现
public class NowSend implements ISendTime {
@Override
public String sendTime() {
return "【立刻发送】";
}
}
//具体实现
public class TimeOut implements ISendTime {
@Override
public String sendTime() {
return "【明天九点发送】";
}
}
//抽象
public abstract class AbastractMsg {
protected IEmergency iEmergency;
protected ISendTime iSendTime;
public AbastractMsg(IEmergency iEmergency, ISendTime iSendTime) {
this.iEmergency = iEmergency;
this.iSendTime = iSendTime;
}
void sendMsg(String msg){
System.out.println(msg);
}
}
//修正抽象
public class CommonMsg extends AbastractMsg {
public CommonMsg(IEmergency iEmergency, ISendTime iSendTime) {
super(iEmergency, iSendTime);
}
@Override
void sendMsg(String msg) {
System.out.println(iSendTime.sendTime() + msg + iEmergency.emergency());
}
}