适配器模式(Adapter Pattern)有时候也称包装样式或者包装,是一种结构型设计模式,它可以将一个类的接口转换成客户端所期望的另一个接口。适配器模式可以让原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式有三种类型:类适配器模式、对象适配器模式和接口适配器模式。
类适配器模式采用多重继承对一个接口与另外一个接口进行匹配,Java 不支持多继承,但可以定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。
接下来就让我们用代码示例来演示一下如何使用适配器模式吧,众所周知鸭脖是一种深受大众喜爱的食物,那我们就用吃鸭脖这一事情做为参照物来演示吧。
鸭脖真好吃
张三开了一家卖鸭脖的店铺,他首先定义一个鸭脖的接口,接口里面定义了 观察和吃两个方法
public interface DuckNeck { // 观察 Object view(); // 吃 void eat(); }
张三接着建立一个鸭脖的实现类RealDuckNeck,这个类实现 DuckNeck
接口,重写了 view
和 eat
方法,通过调用这个实现类顾客们就能开始开心的啃鸭脖了。
public class RealDuckNeck implements DuckNeck{ //鸭脖肉 private Object duckNeckMeat; @Override public Object view() { return duckNeckMeat; } @Override public void eat() { System.out.println("嘎嘎嘎,鸭脖真好吃!"); } }
鸭子这么可爱怎么忍心吃呢
开张后由于鸭脖物美价廉,生意异常火爆,鸭脖供不应求,应该怎么办?这时候张三想起了前段时间因为灭鼠行动积攒了大量的鼠头,而且通过下面的代码我们可以看到鼠头因为只有view的方法,没有eat方法,所以鼠头甚是浪费,这让一向节俭的张三一直都很心疼。
public class MouseHead { private Object mouseHeadMeat; public Object view() { return mouseHeadMeat; } }
思索之间张三突然灵光一闪,想到似乎鼠头和鸭脖有些类似,何不把鼠头加工成鸭脖模样,这样既能解决鸭脖供不应求,也能解决鼠头大量浪费的问题,一箭双雕。于是张三就开始了他对鼠头的加工。
张三首先建立了一个名为DuckNeckFaker,不对是名为DuckNeckAdaper的实现类,个类实现同样 DuckNeck
接口,并且同样重写了 view
和 eat
方法。通过调用这个实现类顾客们又能开始开心的啃鸭脖了,并且不用担心断货了。
public class DuckNeckFaker implements DuckNeck{ MouseHead mouseHead; public Object view() { return fakerMouseHeadToDuckNeck(mouseHead.view()); } @Override public void eat() { System.out.println("吱吱吱,鸭脖真好吃!"); } public Object fakerMouseHeadToDuckNeck(Object mouseHeadMeat) { System.out.println("把鼠头伪装成鸭脖模样"); return "假装自己是个鸭脖"; } }
经过专业机构的检测这真的是一个鸭脖
接下来就让我们建立一个测试类试一下这两个实现类的调用方法,开始开心的啃鸭脖吧
public class EatDuckNeckTest { public static void main(String[] args) { //吃真鸭脖 RealDuckNeck realDuckNeck = new RealDuckNeck(); realDuckNeck.eat(); //吃鼠头鸭脖 MouseHead mouseHead = new MouseHead(); DuckNeckFaker duckNeckFaker = new DuckNeckFaker(mouseHead); duckNeckFaker.eat(); } }
输出结果如下:
嘎嘎嘎,鸭脖真好吃! 吱吱吱,鸭脖真好吃!
鼠鼠是我鸭
优点:
1、可以让任何两个没有关联的类一起运行。
2、提高了类的复用,可以一致化多个不同接口。
3、将现有接口实现类隐藏,增加了类的透明度。
4、灵活性高,可自由适配。
缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,会让系统变得难以维护。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
2、某些适配工作可能非常困难。
那么我们应该在何时考虑使用适配器模式呢?
首先,适配器模式不是软件设计阶段考虑的设计模式,而是解决正在运行中的项目的问题,即已经存在的类或者可能无法改变但是它的方法和需求不匹配的情况,例如这里是被适配类MouseHead缺少了需求要求的eat
方法,view
方法虽然有但是返回又和需求要求的返回不一致,这个时候就适合通过适配器模式适配一下来实现需求。