学习设计模式——适配器模式

本文所有源代码都在我的Github,并且持续更新中…欢迎Star DesignPattern

示例代码

假如我原先的系统都工作在高电压下,代码如下:

public interface HighOutput {


    void workInHigh();

}
public class HighOutPutObject implements HighOutput {
    @Override
    public void workInHigh(){
        System.out.println("workInHigh!");

    }
}
public class Main {
    public static void main(String[] args) {

        HighOutput o = new HighOutPutObject();
        work(o);

    }


    public static void work(HighOutput highOutput) {
        highOutput.workInHigh();

    }
}

但是现在要赚钱了,因为业务需求我们需要兼容一个低电压产品,代码如下:

public class LowOutPutObject {
    public void workInLow(){
        System.out.println(" workInLow");
    }
}

那么我们该如何让上面代码可以完美兼容在一起呢,有些人可能要改动其中的方法名参数,亦或是复杂的判断,因为是测试,可能这不显得麻烦,但是在实际工作的大型项目中,
我们显然不能这么做,因为你不知道这么一改动有多少地方也要改动,所以我们得想个更美好的办法解决这个问题–适配器模式。

适配器模式定义

我们都知道手机电脑的电源适配器,它的作用就是讲220V的电压转化为手机电脑能承受的合适的工作电压。
适配器设计模式也和电源适配器的作用差不多,定义如下:
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法再一起工作的两个类能够在一起工作。

我们用<<设计模式之禅>>中的一张图来理解适配器的作用:

A、 B两个图框代表已经塑模成型的物体A和物体B, 那现在要求把A和B安装在一起使用, 如何安装? 两者的接口不一致,
是不可能安装在一起使用的, 那怎么办? 引入一个物体C, 如图19-6所示。

as
引入了C之后我们可以看到A,B物体能完美结合在一起了。

asd

C就是我们说的适配器,他在中间起到了角色转换的作用。

通用源代码

  • Target目标角色
    该角色定义把其他类转换为何种接口, 也就是我们的期望接口, 例子中的IUserInfo接口就是目标角色。
  • Adaptee源角色
    你想把谁转换成目标角色, 这个“谁”就是源角色, 它是已经存在的、 运行良好的类或对象, 经过适配器角色的包装, 它会成为一个崭新、 靓丽的角色。
  • Adapter适配器角色
    适配器模式的核心角色, 其他两个角色都是已经存在的角色, 而适配器角色是需要新建立的, 它的职责非常简单: 把源角色转换为目标角色, 怎么转换? 通过继承或是类关联的方

Target目标角色:


/*
 * 定义客户端使用的接口,与业务相关
 */
public interface Target {
 /*
 * 客户端请求处理的方法
 */
public void request();
}

源角色,即需要被适配的类

/*
 * 已经存在的接口,这个接口需要配置
 */
public class Adaptee {
 /*
 * 原本存在的方法
 */
    public void specificRequest(){
    //业务代码
    }
}

/*
* 适配器类
*/

适配器类有两种写法,一种可以直接继承源角色并实现Target接口,这种叫类的适配器模式。
class


public class Adapter extends Adaptee implements Target {
    public void request() {
        super.doSomething();
    }
}

另一种就是将源对象委派给适配器,这种叫对象的适配器模式。
object

public class Adapter implements Target{
 /*
 * 持有需要被适配的接口对象
 */
    private Adaptee adaptee;
/*
 * 构造方法,传入需要被适配的对象
 * @param adaptee 需要被适配的对象
 */
    public Adapter(Adaptee adaptee){
        this.adaptee = adaptee;
    }
    @Override
    public void request() {
    //  TODO Auto-generated method stub
        adaptee.specificRequest();
    }

}

建议尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。但两种适配器模式都各有优缺点,我们应该权衡之下决定使用哪一种方法。

关于两种方法的详细优缺点,请看这里dsd

解决方案

public class OutputAdapter extends LowOutPutObject implements HighOutput{




    @Override
    public void workInHigh() {
        super.workInLow();

    }
}

public class Main {
    public static void main(String[] args) {

        HighOutput o = new HighOutPutObject();
        work(o);

        HighOutput o1 = new OutputAdapter();
        work(o1);
    }


    public static void work(HighOutput highOutput) {
        highOutput.workInHigh();

    }
}

ok,完美解决,我们没有改别的地方的代码,就把该接入类完美地兼容到我们原有系统,我们可以看到我们通过OutputAdapter这个类继承了接入类LowOutPutObject并且实现了目标接口HighOutput。
这就是适配器模式的魔力。

现有案例

典型的是SpringMVC中DispatcherServlet中doDispatch方法中根据对应的HandlerMethod获得对应的适配器。然后用适配器处理该HandlerMethod。
SpringMVC中的HandlerAdapters

适配器模式优点和缺点

优点

  • 增加了类的透明性
    想想看, 我们访问的Target目标角色, 但是具体的实现都委托给了源角色, 而这些对高层次模块是透明的, 也是它不需要关心的。

  • 提高了类的复用度
    当然了, 源角色在原有的系统中还是可以正常使用, 而在目标角色中也可以充当新的演员。

  • 灵活性非常好
    某一天, 突然不想要适配器, 没问题, 删除掉这个适配器就可以了, 其他的代码都不用修改, 基本上就类似一个灵活的构件, 想用就用, 不想就卸载。

缺点

过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果
太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

适配器模式应用场景

适配器大多使用在复用类或者新接口不符合我们原先系统,为了使他们能协同工作而采用该设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值