适配器模式又叫做变压器模式,它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法一起工作的两个类能够一起工作,属于结构型设计模式。
适配器适用于以下几种业务场景:
- 已经存在的类,它的方法和需求不匹配的情况。
- 适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案。
适配器模式有3种形式:类适配器、对象适配器、接口适配器。
类适配器
类适配器的原理就是通过继承来实现适配器功能。
class AC220{
public int outputAC220V(){
int output = 220;
System.out.println("输出电压"+output + "V");
return output;
}
}
interface DC5{
int outputDC5V();
}
class PowerAdapter extends AC220 implements DC5{
@Override
public int outputDC5V() {
int adapterInput = super.outputAC220V();
int adapterOutput = adapterInput / 44;
System.out.println("220V 转化成 5V");
return adapterOutput;
}
}
public class Test {
public static void main(String[] args) {
DC5 adapter = new PowerAdapter();
adapter.outputDC5V();
}
}
对象适配器
对象适配器的原理就是通过组合来实现适配器功能。
class AC220{
public int outputAC220V(){
int output = 220;
System.out.println("输出电压"+output + "V");
return output;
}
}
interface DC5{
int outputDC5V();
}
class PowerAdapter implements DC5{
private AC220 ac220;
public PowerAdapter(AC220 ac220){
this.ac220 = ac220;
}
@Override
public int outputDC5V() {
int adapterInput = ac220.outputAC220V();
int adapterOutput = adapterInput / 44;
System.out.println("220V 转化成 5V");
return adapterOutput;
}
}
public class Test {
public static void main(String[] args) {
DC5 adapter = new PowerAdapter(new AC220());
adapter.outputDC5V();
}
}
接口适配器
接口适配器的关注点与类适配器和对象适配器的关注点不太一样,类适配器和对象适配器着重于将系统存在的一个源角色转化成目标接口所需的内容,而接口适配器的使用场景是解决接口方法过多,如果直接实现接口,那么类会多出许多空实现的方法,类显得很臃肿。
接口适配器的主要原理就是利用抽象类实现接口,并空实现接口众多方法。
interface DC{
int output5V();
int output12V();
int output24V();
int output36V();
}
class AC220{
public int outputAC220V(){
int output = 220;
System.out.println("输出电压"+output + "V");
return output;
}
}
class PowerAdapter implements DC{
private AC220 ac220;
public PowerAdapter(AC220 ac220){
this.ac220 = ac220;
}
@Override
public int output5V() {
int adapterInput = ac220.outputAC220V();
int adapterOutput = adapterInput / 44;
System.out.println("220V 转化成 5V");
return adapterOutput;
}
@Override
public int output12V() {
return 0;
}
@Override
public int output24V() {
return 0;
}
@Override
public int output36V() {
return 0;
}
}
public class Test {
public static void main(String[] args) {
DC adapter = new PowerAdapter(new AC220());
adapter.output5V();
}
}
重构第三方登录自由适配的业务场景
import lombok.Data;
/**
* 响应结果
*/
@Data
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;
}
}
@Data
class Member{
private String username;
private String password;
private String mid;
private String info;
}
/**
* 原始登录的逻辑
*/
class PassportService{
/**
* 注册方法
*/
public ResultMsg register(String username, String password){
return new ResultMsg(200,"注册成功",new Member());
}
public ResultMsg login(String username, String password){
return null;
}
}
/**
* 第三方登录接口
*/
interface IPassportForThird{
ResultMsg loginForQQ(String openId);
ResultMsg loginForWechat(String openId);
}
/**
* 创建类适配器
*/
class PassportForThirdAdapter extends PassportService implements IPassportForThird{
@Override
public ResultMsg loginForQQ(String openId) {
return loginForRegist(openId,null);
}
@Override
public ResultMsg loginForWechat(String openId) {
return loginForRegist(openId,null);
}
private ResultMsg loginForRegist(String username ,String password){
if(null == password){
password = "THIRD_EMPTY";
}
super.register(username,password);
return super.login(username,password);
}
}
/**
* 另外根据不同的登录方法,创建不同的Adapter,
*/
interface ILoginAdapter{
boolean support(Object adapter);
ResultMsg login(String id,Object adapter);
}
abstract class AbstractAdapter extends PassportService implements ILoginAdapter{
protected ResultMsg loginForRegist(String username ,String password){
if(null == password){
password = "THIRD_EMPTY";
}
super.register(username,password);
return super.login(username,password);
}
}
class LoginForQQAdapter extends AbstractAdapter{
@Override
public boolean support(Object adaper) {
return adaper instanceof LoginForQQAdapter;
}
@Override
public ResultMsg login(String id, Object adapter) {
if(!support(adapter)) {return null;}
//accessToken
//time
return super.loginForRegist(id ,null);
}
}
class LoginForWechatAdapter extends AbstractAdapter{
@Override
public boolean support(Object adaper) {
return adaper instanceof LoginForWechatAdapter;
}
@Override
public ResultMsg login(String id, Object adapter) {
// if(!support(adapter)) {return null;}
//accessToken
//time
return super.loginForRegist(id ,null);
}
}
class PassportForThirdAdapter2 implements IPassportForThird{
@Override
public ResultMsg loginForQQ(String openId) {
return processLogin(openId,LoginForQQAdapter.class);
}
@Override
public ResultMsg loginForWechat(String openId) {
return processLogin(openId,LoginForWechatAdapter.class);
}
private ResultMsg processLogin(String id, Class<? extends ILoginAdapter> clazz){
try {
ILoginAdapter adapter = clazz.getDeclaredConstructor().newInstance();
if(adapter.support(adapter)){
return adapter.login(id,adapter);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
}
适配器模式和装饰器模式对比
装饰器模式 | 适配器模式 | |
形式 | 是一种非常特别的适配器模式 | 没有层次关系,装饰器模式有层次关系 |
定义 | 装饰器和被装饰器都实现了同一接口,主要目的是为了扩展之后依旧保留OOP关系 | 设配器和被适配器没有必然的联系,通常采用继承或代理的形式进行包装 |
关系 | 满足is-a的关系 | 满足has-a 的关系 |
功能 | 注重覆盖,扩展 | 注重兼容、转换 |
设计 | 前置考虑 | 后置考虑 |
桥接模式
桥接模式(Bridge Pattern)也被为桥梁模式、接口模式或柄体模式,是抽象部分与它的具体实现部分分离,使它们都可以独立变化,属于结构型模式。
桥接模式主要目的是通过组合的方式建立两个类之间的联系,而不是继承。桥接模式的核心在于解耦抽象和实现。
通用写法:
interface IImplementor{
void operationImpl();
}
class ConcreteImplementorA implements IImplementor{
@Override
public void operationImpl() {
System.out.println("ConcreteImplementor A");
}
}
abstract class Abstraction{
protected IImplementor mImplementor;
public Abstraction(IImplementor mImplementor) {
this.mImplementor = mImplementor;
}
public void operation(){
this.mImplementor.operationImpl();
}
}
class RefinedAbstraction extends Abstraction{
public RefinedAbstraction(IImplementor mImplementor) {
super(mImplementor);
}
@Override
public void operation(){
super.operation();
System.out.println("refine operation");
}
}
public class Test {
public static void main(String[] args) {
IImplementor imp = new ConcreteImplementorA();
Abstraction abs = new RefinedAbstraction(imp);
abs.operation();
}
}
桥接模式适用于以下几种业务场景:
- 在抽象和具体实现之间需要增加更多的灵活性的场景
- 一个类存在两个或多个独立变化的维度,而这两个或多个维度都需要独立进行扩展
- 不希望适用继承,或因为多层继承导致系统类的个别数量剧增。
桥接模式的优缺点:
优点:
- 分离抽象部分及具体实现部分
- 提高了系统的扩展性
- 符合开闭原则
- 符合合成复用原则
缺点:
- 增加了系统的理解与设计难度
- 需要正确地识别系统中两个独立变化的维度