一周两个设计模式—设计模式之适配器模式(第二周)
【摘要】 最近时间比较充裕,那就多写一些,顺便提升一下自己的组织能力和书面表达能力,毕竟好的文案也是十分必要的。今天介绍的是结构型模式的适配器模式,适配器模式的对象模式是后续的结构型模型的基础。定义: 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 适配器模式主要分为三种:类的适配器模式、对象的适配器模式和接口的适配器模式从定义中可以...
最近时间比较充裕,那就多写一些,顺便提升一下自己的组织能力和书面表达能力,毕竟好的文案也是十分必要的。今天介绍的是结构型模式的适配器模式,适配器模式的对象模式是后续的结构型模型的基础。
定义:
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式主要分为三种:类的适配器模式、对象的适配器模式和接口的适配器模式
从定义中可以很清楚的知道适配器模式的功能就是转换。
例如不同国家的插座标准不同,如果想使用中国的电器就需要适配器来进行中转。
适配器模式涉及3个角色:
源(Adaptee):需要被适配的对象或类型,相当于插头。
适配器(Adapter):连接目标和源的中间对象,相当于插头转换器。
目标(Target):期待得到的目标,相当于插座。
类适配
继承的关系,Adapter与Adaptee是继承关系,这决定了这是一个类适配器模式。
//源
open class Adaptee {
fun method1(){
Log.v("=======","方法1")
}
}
//目标
interface Target {
fun method1()
fun method2()
}
//适配器
class Adapter:Adaptee(),Target{
override fun method2() {
Log.v("=======","方法2")
}
}
这样就可以直接调用Adaptee中的method1()了。
var adapter = Adapter()
adapter.method1()
adapter.method2()
##对象适配器
与类适配器模式一样,为使客户端能够使用Adaptee类,我们把Adaptee与Target衔接起来。
但这里我们不继承Adaptee,而是把Adaptee封装进Adapter里。这里Adaptee与Adapter是组合关系
//适配器
class ObjectAdapter(adaptee: Adaptee):Target {
private var adaptee = adaptee
override fun method1() {
adaptee.method1()
}
override fun method2() {
Log.v("========","对象模式方法2")
}
}
使用方式:
var adapter = ObjectAdapter(Adaptee())
adapter.method1()
adapter.method2()
类适配器与对象适配器的区别
类适配器使用的是继承的方式,直接继承了Adaptee,所以无法对Adaptee的子类进行适配。
对象适配器使用的是组合的方式,·所以Adaptee及其子孙类都可以被适配。另外,对象适配器对于增加一些新行
为非常方便,而且新增加的行为同时适用于所有的源。
基于组合/聚合优于继承的原则,使用对象适配器是更好的选择。但具体问题应该具体分析,某些情况可能使用类
适配器会适合,最适合的才是最好的。
接口适配器
接口需要实现的方法过多,使用不管有用没用都得实现,使用适配器先默认实现一些功能,只是实现需要实现的功能。
使用抽象类做一次中转实现的,具体方式这里不做介绍了。
来个在项目中的具体使用来看一下
class Task(num:Long):Callable<Long> {
private var num = num
override fun call(): Long {
var r: Long = 0
for (n in 1..num) {
r += n
}
Log.v("========","Result: $r")
return r
}
}
在Task中计算和,这时想在一个Thread中运行这个功能。代码如下:
Callable<Long> callable = new Task(123450000L);
Thread thread = new Thread(callable); // compile error!
thread.start();
发现编译不过!因为Thread接收Runnable接口,但不接收Callable接口,肿么办?
一个办法是改写Task类,把实现的Callable改为Runnable,但这样做不好,因为Task很可能在其他地方作为Callable被引用,改写Task的接口,会导致其他正常工作的代码无法编译。
另一个办法不用改写Task类,而是用一个Adapter,把这个Callable接口“变成”Runnable接口,这样,就可以正常编译:
class RunnableAdapter(callable: Callable<Long>) : Runnable {
var callable = callable
override fun run() {
try {
callable.call()
} catch (e: Exception) {
}
}
}
var callable = Task(1000L)
var thread = Thread(RunnableAdapter(callable))
thread.start()
运行结果:Result: 500500
顺便问个问题,我这个适配器模式是对象适配器模式还是类适配器模式呢?
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)