适配器模式最好在详细设计阶段不要考虑它,它不是为了解决还处于开发阶段的问题,而是解决正在服役的项目问题,没有一个系统分析师会在作详细设计的时候考虑使用适配器模式,这个模式使用的主要场景是扩展应用中。html
注意:项目必定要遵照依赖倒置原则和里氏替换原则,不然即便在适合使用适配器的场合下,也会带来很是大的改造。java
程序设计的原则可参考:程序设计原则设计模式
1.定义:适配器模式(Adapter Pattern)是做为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。ide
2.适配器模式分类:类适配器、对象适配器、接口适配器测试
3.意图:将一个类的接口转换成客户但愿的另一个接口。适配器模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。this
4.主要解决:主要解决在软件系统中,经常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能知足的。spa
5.优势: 一、可让任何两个没有关联的类一块儿运行。 二、提升了类的复用。 三、增长了类的透明度。 四、灵活性好。设计
6.缺点: 一、过多地使用适配器,会让系统很是零乱,不易总体进行把握。好比,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统若是太多出现这种状况,无异于一场灾难。所以若是不是颇有必要,能够不使用适配器,而是直接对系统进行重构。 2.因为 JAVA 至多继承一个类,因此至多只能适配一个适配者类,并且目标类必须是抽象类。htm
原理:经过继承来实现适配器功能。中间件
当咱们要访问的接口A中没有咱们想要的方法 ,却在另外一个接口B中发现了合适的方法,咱们又不能改变访问接口A,在这种状况下,咱们能够定义一个适配器p来进行中转,这个适配器p要实现咱们访问的接口A,这样咱们就能继续访问当前接口A中的方法(虽然它目前不是咱们的菜),而后再继承接口B的实现类BB,这样咱们能够在适配器P中访问接口B的方法了,这时咱们在适配器P中的接口A方法中直接引用BB中的合适方法,这样就完成了一个简单的类适配器。
下面使用员工的信息为例:
需求更改前,员工信息的接口:
public interface IStaff { String getName(); int getAge(); }
需求更改前,员工信息的实现:
public class Staff implements IStaff { private String name; private int age; @Override public String getName() { return name; } @Override public int getAge() { return age; } }
需求更改后,新增员工合同时间信息的接口:
public interface IContract { int getContractTime(); }
需求更改后,新增员工合同时间信息的实现:
public class Contract implements IContract { private int contractTime; @Override public int getContractTime() { return contractTime; } }
需求更改后,新增合同员工信息的实现:
public class ContractStaff extends Contract implements IStaff { private String name; private int age; @Override public String getName() { return name; } @Override public int getAge() { return age; } }
测试代码:
public static void main(String args[]) { /*** 须要更改前,员工信息获取 ***/ IStaff staff = new Staff(); staff.getName(); staff.getAge(); /*** 须要更改后,新增的合同员工的信息获取 ***/ IStaff contractStaff = new ContractStaff(); contractStaff.getName(); contractStaff.getAge(); /*** 新增信息:获取合同员工合同时间 ***/ ((ContractStaff) contractStaff).getContractTime(); }
原理:经过组合来实现适配器功能。
当咱们要访问的接口A中没有咱们想要的方法 ,却在另外一个接口B中发现了合适的方法,咱们又不能改变访问接口A,在这种状况下,咱们能够定义一个适配器p来进行中转,这个适配器p要实现咱们访问的接口A,这样咱们就能继续访问当前接口A中的方法(虽然它目前不是咱们的菜),而后在适配器P中定义私有变量C(对象)(B接口指向变量名),再定义一个带参数的构造器用来为对象C赋值,再在A接口的方法实现中使用对象C调用其来源于B接口的方法。
举个例子:220v机器须要适配110v电压
110v电压接口:
public interface IV110 { int output(); }
110v电压实现:
public class V110 implements IV110 { @Override public int output() { return 110; } }
220v电压接口:
public interface IV220 { int output(); }
220v电压实现:
public class V220 implements IV220 { @Override public int output() { return 220; } }
220v机器的接口:
public interface IMachine220V { boolean is220V(); }
220v机器的实现:
public class Machine220V implements IMachine220V { private int v; public Machine220V(int v){ this.v = v; } @Override public boolean is220V() { return v == 220; } }
110v转220v适配器:
public class Adapter implements IV220{ private IV110 iv110; public Adapter(IV110 iv110) { this.iv110 = iv110; } @Override public int output() { return iv110.output() * 2; } }
测试:
public static void main(String args[]){ /*** 正常状况下:220v机器使用220v电压 ***/ V220 v220 = new V220(); Machine220V machine1 = new Machine220V(v220.output()); System.out.println("machine1 : " + machine1.is220V()); /*** 电压不一样的状况下:220v机器使用110v电压 ***/ V110 v110 = new V110(); Adapter adapter = new Adapter(v110); Machine220V machine2 = new Machine220V(adapter.output()); System.out.println("machine2 : " + machine2.is220V()); }
输出:
machine1 : true
machine2 : true
原理:经过抽象类来实现适配,这种适配稍别于上面所述的适配。
当存在这样一个接口,其中定义了N多的方法,而咱们如今却只想使用其中的一个到几个方法,若是咱们直接实现接口,那么咱们要对全部的方法进行实现,哪怕咱们仅仅是对不须要的方法进行置空(只写一对大括号,不作具体方法实现)也会致使这个类变得臃肿,调用也不方便,这时咱们可使用一个抽象类做为中间件,即适配器,用这个抽象类实现接口,而在抽象类中全部的方法都进行置空,那么咱们在建立抽象类的继承类,并且重写咱们须要使用的那几个方法便可。
目标接口:
public interface IWorkMethod { void method_1(); void method_2(); void method_3(); void method_4(); void method_5(); }
适配器:
public abstract class WorkMethodAdapter implements IWorkMethod { public void method_1(){} public void method_2(){} public void method_3(){} public void method_4(){} public void method_5(){} }
实现类:
public class AWorkMethodAdapter extends WorkMethodAdapter { public void method_1(){ System.out.println("work with method1"); } public void method_2(){ System.out.println("work with method2"); } }
测试:
public static void main(String args[]){ AWorkMethodAdapter aWorkMethod = new AWorkMethodAdapter(); aWorkMethod.method_1(); aWorkMethod.method_2(); }
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,两者主要用于以下场景:
(1)想要使用一个已经存在的类,可是它却不符合现有的接口规范,致使没法直接去访问,这时建立一个适配器就能间接去访问这个类中的方法。
(2)咱们有一个类,想将其设计为可重用的类(可被多处访问),咱们能够建立适配器来将这个类来适配其余没有提供合适接口的类。
以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。
接口适配器使用场景:
(1)想要使用接口中的某个或某些方法,可是接口中有太多方法,咱们要使用时必须实现接口并实现其中的全部方法,可使用抽象类来实现接口,并不对方法进行实现(仅置空),而后咱们再继承这个抽象类来经过重写想用的方法的方式来实现。这个抽象类就是适配器。