首页 > 其他分享 >设计模式探索:适配器模式

设计模式探索:适配器模式

时间:2024-07-09 20:29:19浏览次数:21  
标签:String 探索 适配 适配器 接口 key 设计模式 public

1. 适配器模式介绍

1.1 适配器模式介绍

适配器模式(adapter pattern)的原始定义是:将一个类的接口转换为客户期望的另一个接口,适配器可以让不兼容的两个类一起协同工作。

适配器模式的主要作用是把原本不兼容的接口,通过适配修改做到统一,使得用户方便使用。比如,万能充电器和多接口数据线都是为了适配各种不同的接口。

在这里插入图片描述

为什么要转换接口?

  • 原接口和目标接口都已经存在,不易修改接口代码。
  • 抽象接口希望复用已有组件的逻辑。
1.2 适配器模式结构

适配器模式(Adapter)包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:被适配的角色,它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

适配器模式分为:

  • 类适配器

    在这里插入图片描述

  • 对象适配器

    在这里插入图片描述

两者的区别在于:适配器与适配者的关系。类适配器是继承关系,对象适配器是聚合关系。根据设计原则,聚合优先于继承,应多选用对象适配器。

1.3 代码示例
// 目标接口
public interface Target {
    void request();
}

// 适配者类
public class Adaptee {
    public void specificRequest() {
        System.out.println("适配者中的业务代码被调用!");
    }
}

// 类适配器
public class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        this.specificRequest();
    }
}

// 对象适配器
public class ObjectAdapter implements Target {
    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        this.adaptee.specificRequest();
    }
}

// 测试代码
public class Client {
    public static void main(String[] args) {
        Target classAdapter = new ClassAdapter();
        classAdapter.request();

        Target objectAdapter = new ObjectAdapter(new Adaptee());
        objectAdapter.request();
    }
}

2. 适配器模式在实际开发中的应用

2.1 需求描述

为了提升系统的速度,将一些数据以 K-V 形式缓存在内存中,平台提供 get、put、remove 等 API 以及相关的管理机制。

功能实现的迭代过程,从 HashMap 到 Memcached 再到 Redis,要确保后面再增加新的缓存组件时,能够实现自由的切换,并且还要符合开闭原则。

在这里插入图片描述

设计问题:

  1. 如何在符合开闭原则前提下,实现功能的扩展?
  2. 两种客户端 API 不相同,如何保证自由切换?

使用适配器模式。

2.2 功能实现

使用适配器模式将功能相似的多种第三方组件(实现方案),统一成自己需要的 API,业务代码只依赖已经统一的 API,而不依赖第三方 API。

(1) 定义一个缓存接口,包含 get、put、remove 等操作方法。例如:

public interface Cache {
    void put(String key, Object value);
    Object get(String key);
    void remove(String key);
}

(2) 实现该接口的三个适配器,分别对应 HashMap、Memcached、Redis 三种缓存方案。例如:

// HashMap 适配器
public class HashMapCacheAdapter implements Cache {
    private Map<String, Object> cache = new HashMap<>();

    @Override
    public void put(String key, Object value) {
        cache.put(key, value);
    }

    @Override
    public Object get(String key) {
        return cache.get(key);
    }

    @Override
    public void remove(String key) {
        cache.remove(key);
    }
}

// Memcached 适配器
public class MemcachedCacheAdapter implements Cache {
    private MemcachedClient memcachedClient;

    public MemcachedCacheAdapter(MemcachedClient memcachedClient) {
        this.memcachedClient = memcachedClient;
    }

    @Override
    public void put(String key, Object value) {
        memcachedClient.set(key, 0, value);
    }

    @Override
    public Object get(String key) {
        return memcachedClient.get(key);
    }

    @Override
    public void remove(String key) {
        memcachedClient.delete(key);
    }
}

// Redis 适配器
public class RedisCacheAdapter implements Cache {
    private Jedis jedis;

    public RedisCacheAdapter(Jedis jedis) {
        this.jedis = jedis;
    }

    @Override
    public void put(String key, Object value) {
        jedis.set(key, value.toString());
    }

    @Override
    public Object get(String key) {
        return jedis.get(key);
    }

    @Override
    public void remove(String key) {
        jedis.del(key);
    }
}

(3) 创建工厂类,根据配置文件中的配置来创建相应的缓存适配器。例如:

public class CacheAdapterFactory {
    public static Cache createCacheAdapter(String type) {
        if ("HashMap".equals(type)) {
            return new HashMapCacheAdapter();
        } else if ("Memcached".equals(type)) {
            MemCachedClient memCachedClient = new MemCachedClient();
            return new MemcachedCacheAdapter(memCachedClient);
        } else if ("Redis".equals(type)) {
            Jedis jedis = new Jedis("localhost", 6379);
            return new RedisCacheAdapter(jedis);
        } else {
            throw new IllegalArgumentException("Invalid cache type: " + type);
        }
    }
}

使用时,只需要调用工厂类的 createCacheAdapter 方法,传入缓存类型即可获取相应的缓存适配器。例如:

public class Client {
    public static void main(String[] args) {
        Cache cache = CacheAdapterFactory.createCacheAdapter("Redis");
        cache.put("key", "value");
        Object result = cache.get("key");
        cache.remove("key");
    }
}

3. 适配器模式总结

优点:

  1. 解耦合: 适配器模式允许两个没有直接关联的类协同工作,降低了它们之间的耦合度。
  2. 提高复用性: 通过适配器,可以重用现有的类,而不需要修改它们的代码。
  3. 统一接口: 适配器模式提供了一种方法来统一多个不同的接口,使得它们可以被统一对待。
  4. 隐藏实现: 适配器模式隐藏了现有类的实现细节,只暴露出需要的接口。
  5. 灵活性: 可以根据需要自由地适配不同的类,提供了高度的灵活性。

缺点:

  1. 单一适配限制: 使用类适配器时,一次最多只能适配一个适配者类,这可能限制了其应用范围。
  2. 系统复杂度: 如果过度使用适配器,可能会导致系统结构变得复杂,难以理解和维护。

适用场景:

  1. 接口统一: 当需要统一多个类的接口时,适配器模式可以有效地将它们适配到一个统一的接口。
  2. 兼容性需求: 当现有的接口无法修改,但需要与其他系统或模块兼容时,适配器模式可以提供解决方案。

标签:String,探索,适配,适配器,接口,key,设计模式,public
From: https://blog.csdn.net/qq_26893655/article/details/140305195

相关文章

  • 设计模式学习(二)工厂模式——抽象工厂模式+注册表
    目录前言使用简单工厂改进使用注册表改进参考文章前言在上一篇文章中我们提到了抽象工厂模式初版代码的一些缺点:①客户端违反开闭原则②提供方违反开闭原则。本文将针对这两点进行讨论使用简单工厂改进对于缺点①,我们可以使用简单工厂的思路来改进抽象工厂的初版代码。对于上......
  • 运维锅总详解设计模式
    本首先简介23种设计模式,然后用Go语言实现这23种设计模式进行举例分析。希望对您理解这些设计模式有所帮助!一、设计模式简介设计模式是软件设计中用于解决常见设计问题的一套最佳实践。它们不是代码片段,而是解决特定问题的通用方案。设计模式分为三大类:创建型模式、结构型......
  • 设计模式之工厂模式
    1.前言最近在看《大话设计模式》这本书,虽然大学也学过设计模式,但是那时候还没有进行过开发,那么多的设计模式,看了也不知道用在哪种场景,最近又突然有时间了,就想着重新理解一遍软件的设计模式,本篇博客的原地址为runoob2.工厂模式的简介工厂模式(FactoryPattern)是Java中最常用的......
  • 设计模式之策略模式和工厂模式的区别
    1.前言本篇博客转载于策略模式与工厂模式比较2.区别这段时间看了一些设计模式,看到策略模式与工厂模式的时候,总是感觉他们很相似,不要区分,到具体的场景了你可能还在徘徊到底用工厂还是策略呢?这几天就想写一篇关于策略模式与工厂模式区别的文章,但一直没思路,昨天跟淘宝mm聊了聊,今天......
  • 设计模式六大原则
    一、单一职责原则(SingleResponsibilityPrinciple)定义:一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2......
  • 探索Google AI Studio的无限可能:从设计到代码的全新体验
    探索GoogleAIStudio的无限可能:从设计到代码的全新体验在2024年的GoogleI/O开发者大会上,Google展示了一项令人兴奋的实时演示:Gemini能够将应用程序UI的线框草图转换为JetpackCompose代码,直接在AndroidStudio中进行。这一功能基于Gemini的核心能力,虽然我们仍在不断优化......
  • 【C语言】指针(3):探索-不同类型指针变量
    目录一、字符指针变量二、数组指针变量三、二维数组传参的本质四、函数指针变量4.1函数指针变量4.2函数指针变量的使用4.3函数指针变量的拓展五、函数指针数组六、转移表的应用通过深入理解指针(1)和深入理解指针(2),我们对指针有了一个初步的了解,学会了一级指针、二......
  • 2024.07.09【读书笔记】|医疗科技创新流程(第二章 创新创造 概念探索与测试案例分析1)
    案例一:Oculeve-神经刺激治疗干眼症背景与挑战干眼症(DryEyeDisease,DED)是一种常见的眼部疾病,影响着数百万美国人的生活质量。该病症由泪液不足或蒸发过快引起,导致眼表炎症、疼痛、灼热感、异物感和视力受损。Oculeve团队认识到,尽管市场上有人工泪液等治疗方法,但这些方......
  • 探索前端报表:如何实现无预览打印解决方案或静默打印?
    最新技术资源(建议收藏)https://www.grapecity.com.cn/resources/在前端开发中,除了将数据呈现后,我们往往需要为用户提供,打印,导出等能力,导出是为了存档或是二次分析,而打印则因为很多单据需要打印出来作为主要的单据来进行下一环节的票据支撑,而前端打印可以说是非常令人头疼的一......
  • [JS]设计模式
    介绍设计模式就是在面向对象软件设计过程中,针对特定问题的简洁而优雅的解决方案目前说到设计模式,一般指<设计模式:可复用面向对象软件的基础>一书中提到的23种常见软件设计模式工厂模式在JavaScript中,工厂模式的表现形式就是一个调用即可返回新对象的函数<scri......