设计模式:适配器模式

发布于:2024-05-08 ⋅ 阅读:(30) ⋅ 点赞:(0)

设计意图       

         适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
        在某些时候,客户期望获得某种功能接口但现有的接口无法满足客户的需求,例如美国的正常供电电压为110V,一个中国人带了一款中国制造电器去美国,这个电器必须要在220V电压下才能充电使用。这种情况下,客户(中国人)的期望接口是有一个220V的电压为电器充电,但实际的接口是仅有一个110V的电压供电器充电,这种情况下就需要采用一根电压转换器(适配器)使得110V的电压能够转换为220V的电压,供客户使用。

        将一个类的接口转换成客户希望的另外一个接口,这就是适配器需要做的事情,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适用条件
        系统需要使用现有的类,而此类的接口不符合系统的需要(核心需求)。
想要建立一个可以重复使用的适配器类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口,但通过适配器使得它们都具有一致的接口。
        通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

设计
        设计通常有两种方式实现适配器模式,一种是类适配器,类适配器目前已不太使用,另一种实现方式是对象适配器,通常情况下采用对象适配器会使得代码更易扩展与维护。
        不管采用何种方式,其基本的实现思想都是:对现有接口的实现类进行扩展,使其实现客户期望的目标接口。
        类适配器通过继承现有接口类并实现目标接口,这样的话会使得现有接口类完全对适配器暴露,使得适配器具有现有接口类的全部功能,破坏了封装性。此外从逻辑上来说,这也是不符合常理的,适配器要做的是扩展现有接口类的功能而不是替代,类适配器只有在特定条件下会被使用。
对象适配器持有现有接口类一个实例,并扩展其功能,实现目标接口。这是推荐的方式,优先采用组合而不是继承,会使得代码更利于维护。此外,这也是非常符合常理的——“给我一根线,让我来给他加长到5m,我并不需要知道这跟线是什么组成的,因为我的工作就是让线加长到5m”——我们扩展了相应功能而并不关心其具体实现。
对象适配器
适配器的组成要素
•Target:客户期望获得的功能接口(220V电压供电)。
• Cilent:客户,期望访问Target接口(客户期望能有220V电压)。
•Adaptee:现有接口,这个接口需要被适配(现有110V电压供电,需要被适配至220V)。
• Adapter:适配器类,适配现有接口使其符合客户需求接口(适配110V电压,使其变为220V电压)。
对象适配器结构图:


适配器模式总结
优点
•可以让任何两个没有关联的类一起运行。
•提高了类的复用,可以一致化多个不同接口。
•将现有接口实现类隐藏,增加了类的透明度。
•灵活性高,可自由适配。
缺点
•过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实
现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构.
•某些适配工作可能非常困难,例如让房子飞起来。
•当我们有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
注意事项:

适配器不是在详细设计时添加的,而是解决正在服役的项目的问题,即现有接口可能无法改变(去美国不可能把人家110V电压供给改成220V电压供给)。
剖析适配器模式在 Java 日志中的应用
Java 中有很多日志框架,在项目开发中,我们常常用它们来打印日志信息。其中,比较常用的有 log4j、logback,以及 JDK 提供的 JUL(java.util.logging)和 Apache 的 JCL(Jakarta Commons Logging)等。


大部分日志框架都提供了相似的功能,比如按照不同级别(debug、info、warn、erro.....)打印日志等,但它们却并没有实现统一的接口。这主要可能是历史的原因,它不像 JDBC 那样,一开始就制定了数据库操作的接口规范。

案例

public interface UserService {
    public Map findById();
    public List<Map> findUsers();
}
public class UserServiceImpl implements UserService{
    @Override
    public Map findById() {
        Map map = new HashMap();
        map.put("user_id",1234);
        map.put("username","shengnan");
        return map;
    }

    @Override
    public List<Map> findUsers() {
        List<Map> list = new ArrayList<>();
        for (int i = 0; i <= 10; i++) {
            Map map = new LinkedHashMap();
            map.put("user_id",new Random().nextInt(1000));
            map.put("username","user" + i);
            list.add(map);
        }
        return list;
    }
}
public interface SpecUserService {
    public String findByJUserId();
    public String findJUsers();
}
public class SpecUserServiceAdaptor implements SpecUserService{
    private UserService userService;
    public SpecUserServiceAdaptor(UserService userService){
        this.userService = userService;
    }
    @Override
    public String findByJUserId() {
        Map map = userService.findById();
        String json = new Gson().toJson(map);
        return json;
    }

    @Override
    public String findJUsers() {
        List<Map> users = userService.findUsers();
        String json = new Gson().toJson(users);
        return json;
    }
}
public class AdaptorDemo {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        SpecUserService specUserService =new SpecUserServiceAdaptor(userService);
        String jUsers = specUserService.findJUsers();
        System.out.println(jUsers);
    }
}