设计模式 - 适配器模式,就该这样学!

本文介绍了适配器模式,如何将不兼容的接口转换,如博客系统中文章分表的案例。阐述了适配器类、目标接口和优点,以及如何利用该模式在不改动原有代码的情况下扩展功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、适配器模式

一句话概括结构式模式

1.1、适配器模式概述

1.3、案例(项目实战)

1.4、优缺点(对象适配器模式)

1.5、应用场景


一、适配器模式


一句话概括结构式模式

教你将类和对象结合再一起形成一个更强大的结构.

1.1、适配器模式概述

将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的接口能一起工作.

比如,你有一个台灯的充电线式两孔的插头,而现在只有一个插座是三孔的,此时你可能就需要一个给这个三孔插座接一个插板,这个插板上就有 两孔的、三孔的....  这样你的台灯就能用了对吧.

并且如果这个插板对应到我们程序中,如果是一个类的话,将来想要支持更多插孔,就直接引入即可. 不需要做太大的调整,满足开闭原则.

适配器模式包含以下主机角色:

  1. 目标接口:当前客户所期待的接口,它可以是抽象类或者接口(上述的 两孔插座).
  2. 适配者类:是被访问的现存组件库中的接口(上述的 两孔插头).
  3. 适配器类:是一个转换器,通过继承或引用目标接口,实现适配者类的所有方法,就可以实现转换效果.

1.3、案例(项目实战)

例如有一个博客系统,其中文章表被分表了,分成了 文章信息表、文章统计信息表 这两张表,此时就可以使用一个适配器,来对文章的信息的 CRUD 进行统一处理.

a)适配者类:文章信息数据库操作如下

data class ArticleInfo(
    val id: Long,
    val title: String,
    val content: String,
)

//这里的实现就是对数据库的操作
interface ArticleInfoRepo {

    fun queryById(id: Long): ArticleInfo

    fun pageInfo(offset: Int, limit: Int): PageResp<ArticleInfo>

}

b)适配者类:文章统计信息数据库操作如下:

data class ArticleStat (
    val id: Long,
    val pv: Long,
    val likeCnt: Long ,
    val collectCnt: Long,
    val commentCnt: Long,
)

//这里的实现就是对数据库的操作
interface ArticleStatRepo {

    fun queryById(id: Long): ArticleStat

    fun pageStat(offset: Int, limit: Int): PageResp<ArticleStat>

}

c)目标接口

interface ArticleDataHandler {

    fun queryArticleById(id: Long): ArticleVo

    fun pageArticleById(offset: Int, limit: Int): PageResp<ArticleVo>

    //......

}

data class ArticleVo (
    val id: Long,
    val title: String,
    val content: String,
    val pv: Long,
    val likeCnt: Long ,
    val collectCnt: Long,
    val commentCnt: Long,
)

d)适配器类

//@Component 表示这是个组件
class ArticleDataAdapter ( //构造方法注入
    val infoRepo: ArticleInfoRepo,
    val statRepo: ArticleStatRepo
): ArticleDataHandler {

    override fun queryArticleById(id: Long): ArticleVo {
        val info = infoRepo.queryById(id)
        val stat = statRepo.queryById(id)
        return map(info, stat)
    }


    override fun pageArticleById(offset: Int, limit: Int): PageResp<ArticleVo> {
        val pageInfo = infoRepo.pageInfo(offset, limit)
        val pageStat = statRepo.pageStat(offset, limit)
        return map(pageStat, pageStat)
    }

    private fun map(info: PageResp<ArticleStat>, stat: PageResp<ArticleStat>): PageResp<ArticleVo> {
        TODO("Not yet implemented")
    }

    private fun map(info: ArticleInfo, stat: ArticleStat): ArticleVo {
        TODO("Not yet implemented")
    }

}

分析: 

将来如果想要继续对文章分表,那么直接引入相应的 Repo 即可,在适配器类中进行扩展即可.

1.4、优缺点(对象适配器模式)

优点

1. 适配现有类,且不修改类:在不改变现有类的基础上,实现现有类和目标类的接口的匹配.

2. 符合 合成/聚合 复用原则:持有引用,而不继承.

3. 符合开闭原则:如果引入新的目标接口,只需要在适配器类中进行扩展,不需要修改原代码.

缺点:

增加复杂性:编写适配器类时,要考虑全面,包括适配者和目标类.

1.5、应用场景

1. 以前开发的系统中存在满足当前业务所需要的类,但是接口和当前业务所需接口不一致.

2. 第三方提供的组件,但是组件接口定义和自己要求的接口定义不同.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值