【JAVA设计模式】适配器模式(Adapter)
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。
案例
假设要为某个系统添加日志管理的功能,开发人员按照需求,将日志保存于文件当中。 为了方便,我们大大简化了系统。
/** * 日志文件操作接口 * Created by jerry on 16-4-20. */
public interface LogFileOperateApi {
    /** * 从文件里读取日志 */
    public void getFileLog();
    /** * 将日志写入文件当中去 */
    public void addFileLog();
    /** * 删除一条日志 */
    public void removeFileLog();
}
/** * 文件操作接口的实现类 * Created by jerry on 16-4-20. */
public class LogFileOperate implements LogFileOperateApi {
    /** * 从文件里读取日志 */
    @Override
    public void getFileLog() {
        System.out.println("读取文件日志");
    }
    /** * 将日志写入文件当中去 */
    @Override
    public void addFileLog() {
        System.out.println("增加文件日志");
    }
    /** * 删除一条日志 */
    @Override
    public void removeFileLog() {
        System.out.println("删除文件日志");
    }
}
客户端调用如下:
/** * 测试 * Created by jerry on 16-4-20. */
public class Client {
    public static void main(String[] args) {
        // 文件日志
        LogFileOperateApi fileLog = new LogFileOperate();
        fileLog.addFileLog();
        fileLog.getFileLog();
        fileLog.removeFileLog();
    }
}
输出结果如下:
增加文件日志
读取文件日志
删除文件日志
此时,假设来了一个新的需求,想要使用数据库日志管理,而这套管理程序代码已经由他人写好,但是发现其代码的接口与现有文件日志系统的接口不同,如下所示
import java.util.List;
/** * 操作数据库日志 * Created by jerry on 16-4-20. */
public interface LogDBOperateApi {
    /** * 从文件里读取日志 */
    public void getDBLog();
    /** * 将日志写入文件当中去 */
    public void addDBLog();
    /** * 删除一条日志 */
    public void removeDBLog();
}
/** * Created by jerry on 16-4-20. */
public class LogDBOperate implements LogDBOperateApi {
    /** * 从文件里读取日志 */
    @Override
    public void getDBLog() {
        System.out.println("读取数据库日志");
    }
    /** * 将日志写入文件当中去 */
    @Override
    public void addDBLog() {
        System.out.println("增加数据库日志");
    }
    /** * 删除一条日志 */
    @Override
    public void removeDBLog() {
        System.out.println("删除数据库日志");
    }
}
那么现在带来的问题是如何转换成使用数据库管理日志。 当然最笨的办法是直接修改客户端调用代码,但是这在有时却是不可行的,假设调用日志的代码分散中系统各处,那么修改这样的代码简直就是灾难。
使用模式的情况
最基本的适配器模型的UML图如下:
- Client:客户端,需要调用request方法实现自己的功能
 - Target:接口。
 - Adapter:适配器类。实现Target接口,但在实现中,转而调用Adaptee中方法。
 
可能说的比较抽象,还是以上述案例为例,Target接口相当于上面的操作文件日志接口,即LogFileOperateApi,Adaptee相当于LogDBOperate,而Adapter如下:
/** * Created by jerry on 16-4-20. */
public class Adapter implements LogFileOperateApi {
    private LogDBOperateApi adaptee;
    public Adapter(LogDBOperateApi adaptee) {
        this.adaptee = adaptee;
    }
    /** * 从文件里读取日志 */
    @Override
    public void getFileLog() {
        adaptee.getDBLog();
    }
    /** * 将日志写入文件当中去 */
    @Override
    public void addFileLog() {
        adaptee.addDBLog();
    }
    /** * 删除一条日志 */
    @Override
    public void removeFileLog() {
        adaptee.removeDBLog();
    }
}
总结下写一个适配器类的步骤:
- 实现Target接口
 - 创建一个变量保存Adaptee类对象的adaptee
 - 创建一个构造函数,接受Adaptee类,并赋值给adaptee
 - 在接口的实现方法中调用adaptee相应的方法
 
此时客户端调用只要进行如下修改即可:
/** * 测试 * Created by jerry on 16-4-20. */
public class Client {
    public static void main(String[] args) {
        // 文件日志
// LogFileOperateApi fileLog = new LogFileOperate();
        //改为数据库日志
        LogFileOperateApi fileLog = new Adapter(new LogDBOperate());
        fileLog.addFileLog();
        fileLog.getFileLog();
        fileLog.removeFileLog();
    }
}
总结
适配器本质: 转换匹配,复用功能。
何时使用适配器模式:
- 如果你想要使用一个已经存在的类,但是它的接口不符合你的需求,这种情况可以使用适配器模式,来把已有的实现转化成你需要的接口。
 - 如果你想创建一个可以复用的类,这个类可能和一些不兼容的类一起工作,这种情况下可以使用适配器模式,需要什么适配什么。
 
                    
                
                
            
        
浙公网安备 33010602011771号