重修计划模式-结构型-适配器模式

打印 上一主题 下一主题

主题 572|帖子 572|积分 1720

重修计划模式-结构型-适配器模式

   将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作
  适配器模式(Adapter Pattern)允许将一个类的接口变更成客户端所等待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类可以或许在一起工作。简朴来说,适配器办理的就是接口不兼容题目,引入适配器充当中间桥梁,从而让不兼容接口协同工作。
适配器模式的三个角色:

  • 目标接口(Target):客户端所期望的接口,可以是抽象类、接口或具体的类。
  • 必要适配的类(Adaptee):必要适配的类或接口,它通常是一个已经存在的、与客户端期望的接口不兼容的类。
  • 适配器(Adapter):适配器类的核心,负责将 Adaptee 的接口转换成 Target 的接口。适配器类通常是具体类,通过继承或组合的方式与 Adaptee 发生关联。
适配器模式的两种实现:


  • 类适配器:利用继承来实现适配。
    通过继承将一个接口与另一个接口举行匹配,比力恰当 Adaptee 和 Target 界说相似的场景,这种场景利用继承可以让代码少一些,代码可读性会高一些。
  • 对象适配器:利用组合来实现适配。
    通过组合的方式,利用适配器类必要适配的类(Adaptee)的实例包装起来,适配器类通过调用 Adaptee 的实例方法来实现目标接口。
举个例子,步调中存在这样的逻辑,从数据源A(DataSourceA) 处获取用户数据,并调用 saveUser 举行用户数据的处置处罚,saveUser 只接收 IUser 接口范例的数据。这时需求变更,必要扩展出另一个数据源B(DataSourceB),但该数据源返回的数据范例为 UserB,saveUser 并不能接收 UserB 范例数据,代码表示如下:
  1. //Target
  2. interface IUser {
  3.     fun getName(): String
  4.     fun getAge(): Int
  5.     fun getSign(): String?
  6. }
  7. //数据源A
  8. object DataSourceA {
  9.     //模拟返回数据
  10.     fun getData(): IUser {
  11.         return object: IUser {
  12.             override fun getName(): String = "白泽"
  13.             override fun getAge(): Int = 18
  14.             override fun getSign(): String? = "人生得意须尽欢"
  15.         }
  16.     }
  17. }
  18. //Adaptee
  19. class UserB(val nick: String, val birthday: String)
  20. //新增的数据源B
  21. object DataSourceB {
  22.    
  23.     //模拟返回数据
  24.     fun getData(): UserB {
  25.         return UserB("白泽", "1996")
  26.     }
  27. }
  28. //处理User数据
  29. fun saveUser(user: IUser) {
  30.     //处理user相关逻辑
  31.     println("处理用户信息 name:${user.getName()} age:${user.getAge()} sign:${user.getSign()}")
  32. }
  33. //调用处:
  34. fun main() {
  35.     val user1 = DataSourceA.getData()
  36.     saveUser(user1) //正常调用
  37.     val user2 = DataSourceB.getData()
  38.     //saveUser(user2) //类型不兼容
  39. }
复制代码
1.利用继承类方式实现适配器,创建适配器(ExtendUser),让其继承必要适配的类(UserB),并实现目标接口(IUser ),并覆写干系逻辑:
  1. //适配器-继承
  2. class ExtendUser(nick: String, birthday: String): UserB(nick, birthday), IUser {
  3.     override fun getName(): String {
  4.         return super.nick
  5.     }
  6.     override fun getAge(): Int {
  7.         return Date().year - (super.birthday.toIntOrNull() ?: 0)
  8.     }
  9.     override fun getSign(): String? {
  10.         return null
  11.     }
  12. }
  13. object DataSourceB {
  14.     ...
  15.        
  16.     //新增返回ExtendUser类型方法
  17.     fun getDataExtend(): ExtendUser {
  18.         return ExtendUser("白泽", "1996")
  19.     }
  20. }
  21. //调用处:
  22. fun main() {
  23.     val user2 = DataSourceB.getDataExtend()
  24.         saveUser(user2)
  25. }
复制代码
其实更优方式是让 UserB 直接实现 IUser 接口,这里为了明确三个适配器角色还是额外抽出一个适配器类,但牢记计划模式不能死记硬背,随机应变才是代码计划的核心。
2.通过组合方式实现适配器,创建适配器(AdapterUser),其内持有必要适配的类的实例(UserB),并实现目标接口(IUser):
  1. //适配器-组合
  2. class AdapterUser(val user: UserB): IUser {
  3.     override fun getName(): String {
  4.         return user.nick
  5.     }
  6.     override fun getAge(): Int {
  7.         return Date().year - (user.birthday.toIntOrNull() ?: 0)
  8.     }
  9.     override fun getSign(): String? {
  10.         return null
  11.     }
  12. }
  13. fun main() {
  14.     val user2 = DataSourceB.getData()
  15.     val adapterUser = AdapterUser(user2)
  16.     saveUser(adapterUser)
  17. }
复制代码
这两种方式都可以实现适配器模式,区别在于以下几点:

  • 继承方式会有语言层单继承的限制,假如 Adaptee 和 Target 都不是接口,继承方式就无能为力了。
  • 继承恰当 Adaptee 和 Target 接口界说大部门相同场景,用代码语义相似性来让可读性更高;组合偏重部门可以在整体内自由变革,恰当更加机动的场景。
代理、桥接、装饰器、适配器 4 种计划模式的区别:
代理、桥接、装饰器、适配器,这 4 种模式的代码结构非常相似。笼统来说,它们都可以称为 Wrapper 模式,也就是通过 Wrapper 类二次封装原始类。
只管代码结构相似,但这 4 种计划模式的用意完全差别,也就是说要办理的题目、应用场景差别,这也是它们的主要区别。这里我就简朴说一下它们之间的区别。
代理模式:代理模式在不改变原始类接口的条件下,为原始类界说一个代理类,主要目标是控制访问,独立思索非干系功能,这是它跟装饰器模式最大的差别。
桥接模式:桥接模式的目标是将抽象部门和实现部门分离,从而让它们可以较为容易、也相对独立地加以改变。
装饰器模式:装饰者模式在不改变原始类接口的情况下,对原始类功能举行增强,并且支持多个装饰器的嵌套利用。
适配器模式:适配器模式既可以视作调停策略,也可以视作统一规范。适配器提供跟原始类差别的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。
适配器模式利用场景
一方面适配器模式可以看作一种“补偿模式”,用来调停计划上的缺陷,和谐规避接口不兼容的题目。另一方面,适配器也可以在计划之初特意为变革预留接口,定制适配规范。
好比 Android 中列表控件 RecyclerView 就是适配器模式的经典运用,RecyclerView.Adapter 是抽象出来的适配规范,RecyclerView 内部只必要关注 View 的缓存,绘制和展示即可,而无需关注具体 View 是哪个,如何绑定数据等操作,这些逻辑都由调用方本身实现适配器并处置处罚。 JVM 虚拟机也可以用适配器的思想去看,JVM 就相当于一个适配器,它向下屏蔽了各种体系的差异,任何语言只必要遵循 JVM 的干系规范,都可以运行在 JVM 虚拟机上,好比 Java、Kotlin、Groovy、JRuby、Jython、Scala等语言都是基于 JVM 规范而开发出来的。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王國慶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表