与电源适配器类似,在适配器模式中引入了一个被称为适配器(Adapter)的包装类,而它所包装的对象称为适配者(Adaptee),即被适配的类。适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。所以,适配器让那些因为接口不兼容而不能交互的类能够一块儿工做。java
适配器模式能够将一个类的接口和另外一个类的接口匹配起来,而无须修改原来的适配者接口和抽象目标类接口。git
将一个接口转换成客户但愿的另外一个接口,使接口不兼容的那些类能够一块儿工做,其别名为包装器(Wrapper)。适配器模式既能够做为类结构型模式,也能够做为对象结构型模式。算法
在对象适配器模式结构图中包含以下几个角色:数据库
● Target(目标抽象类):目标抽象类定义客户所需接口,能够是一个抽象类或接口,也能够是具体类。编程
● Adapter(适配器类):适配器能够调用另外一个接口,做为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它经过继承Target并关联一个Adaptee对象使两者产生联系。设计模式
● Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口须要适配,适配者类通常是一个具体类,包含了客户但愿使用的业务方法,在某些状况下可能没有适配者类的源代码。app
Sunny 软件公司 OA 系统须要提供一个加密模块,将用户机密信息(如口令、邮箱等)加密以后再存储在数据库中,系统已经定义好了数据库操做类。为了提升开发效率,现须要重用已有的加密算法,这些算法封装在一些由第三方提供的类中,有些甚至没有源代码。试使用适配器模式设计该加密模块,实如今不修改现有类的基础上重用第三方加密方法。框架
结构图设计以下:ide
代码以下:测试
/** * Author: YiFan * Date: 2018/12/17 12:29 * Description: 数据库操做接口 */ public interface IDataBaseOperation { /** * 用户信息加密 * @param info 用户口令、邮箱 * @return 加密后的用户口令、邮箱 */ String informationEncryption(String info); } /** * Author: YiFan * Date: 2018/12/17 12:31 * Description: 适配者类 */ public class Adaptee { /** * 经过MD5算法加密用户信息 * @param info 用户口令、邮箱 * @return 加密的用户口令、邮箱 */ public String informationEncryptionByMD5(String info) { return MD5Util.MD5(info); } } /** * Author: YiFan * Date: 2018/12/17 12:30 * Description: 适配器类 */ public class EncryptionAdapter implements IDataBaseOperation { private Adaptee adaptee; public EncryptionAdapter() { adaptee = new Adaptee(); } @Override public String informationEncryption(String info) { return adaptee.informationEncryptionByMD5(info); } } /** * Author: YiFan * Date: 2018/12/17 22:52 * Description: MD5加密算法 */ public class MD5Util { // MD5加密算法 public static String MD5(String key) { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; try { byte[] btInput = key.getBytes(); // 得到MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 mdInst.update(btInput); // 得到密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { return null; } } } /** * Author: YiFan * Date: 2018/12/17 22:42 * Description: 用户类 */ public class User { // 用户昵称 private String nickname; // 用户口令 private String password; // 用户电话 private String tel; // 用户邮箱 private String email; public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } /** * Author: YiFan * Date: 2018/12/17 12:34 * Description: 客户端测试类 */ public class Client { public static void main(String[] args) { User user = new User(); user.setPassword("123456789"); user.setEmail("xyfaqq@163.com"); // 针对接口编程 IDataBaseOperation dataBaseOperation; // 实例化对象 dataBaseOperation = new EncryptionAdapter(); // 加密的用户密码 String passwordEncryption = dataBaseOperation.informationEncryption(user.getPassword()); // 加密的用户邮箱 String emailEncryption = dataBaseOperation.informationEncryption(user.getEmail()); System.out.println("加密前用户口令:" + user.getPassword() + ",加密后用户口令:" + passwordEncryption); System.out.println("加密前用户邮箱:" + user.getEmail() + ", 加密后用户邮箱:" + emailEncryption); } }
直接结果为:
加密前用户口令:123456789,加密后用户口令:25F9E794323B453885F5181F1B624D0B 加密前用户邮箱:xyfaqq@163.com, 加密后用户邮箱:B187339EF36A225D8A161790844BC8A1
适配器模式将现有接口转化为客户类所指望的接口,实现了对现有类的复用,它是一种使用频率很是高的设计模式,在软件开发中得以普遍应用,在Spring等开源框架、驱动程序设计(如 JDBC 中的数据库驱动程序)中也使用了适配器模式。
(1) 将目标类和适配者类解耦,经过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
(2) 增长了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,并且提升了适配者的复用性,同一个适配者类能够在多个不一样的系统中复用。
(3) 灵活性和扩展性都很是好,经过使用配置文件,能够很方便地更换适配器,也能够在不修改原有代码的基础上增长新的适配器类,彻底符合“开闭原则”。
类适配器模式的缺点以下:
(1) 对于Java、C#等不支持多重类继承的语言,一次最多只能适配一个适配者类,不能同时适配多个适配者;
(2) 适配者类不能为最终类,如在Java中不能为final类,C#中不能为sealed类;
(3) 在Java、C#等语言中,类适配器模式中的目标抽象类只能为接口,不能为类,其使用有必定的局限性。
对象适配器模式的缺点以下:
与类适配器模式相比,要在适配器中置换适配者类的某些方法比较麻烦。若是必定要置换掉适配者类的一个或多个方法,能够先作一个适配者类的子类,将适配者类的方法置换掉,而后再把适配者类的子类当作真正的适配者进行适配,实现过程较为复杂。
(1) 系统须要使用一些现有的类,而这些类的接口(如方法名)不符合系统的须要,甚至没有这些类的源代码。
(2) 想建立一个能够重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在未来引进的类一块儿工做。