现在我们来学习适配器模式,现在我们建一个包,在结构型这个包下,建一个adapter,我们适配器模式呢,
主要是分为,类适配器模式,还有对象适配器模式,那这两个适配器模式,最重要的区别,就是一个通过组合,一个通过继承,
那我们都来演示一下,首先创建一个包,classadapter,类适配器模式,那这里说一下这个角色,第一个是被适配者
这个类图还是很清晰的,首先Adapter它继承了Adaptee被适配者,同时实现了目标接口,那这样其实Target其实是两种实现的,
一种是具体的Target实现类,另外一种通过Adapter,他的实现类就变成了Adaptee的adapteeRequest
package com.learn.design.pattern.structural.adapter.classadapter;
/**
*
* @author Leon.Sun
*
*/
public class Adaptee {
/**
* 这里面有一个方法
* 这个方法是被适配者独有的
* 我们起名就叫adapteeRequest
* 被适配者的方法
* 那下面第二个角色登场
* 我们目标要实现成什么样的呢
*
*
*/
public void adapteeRequest(){
System.out.println("被适配者的方法");
}
}
package com.learn.design.pattern.structural.adapter.classadapter;
/**
* 对于Target它是一个接口
* 他可以有很多实现类
* 现在写一个Target的实现类
* 具体的Target
*
*
* @author Leon.Sun
*
*/
public interface Target {
/**
* 定义成接口
* 看到这两个方法是不一样的
* Target里面是request
* Adaptee里面是adapteeRequest
*
*/
void request();
}
package com.learn.design.pattern.structural.adapter.classadapter;
/**
* 他实现Target
*
*
* @author Leon.Sun
*
*/
public class ConcreteTarget implements Target {
/**
* concreteTarget目标方法
* 那具体的Target也有了
* 现在我们就要通过Adaptee适配者适配这个被适配者
* 来达到Target这个目标
* 我们创建Adapter
*
*
*/
@Override
public void request() {
System.out.println("concreteTarget目标方法");
}
}
package com.learn.design.pattern.structural.adapter.classadapter;
/**
* 由他继承被适配者Adaptee
* 然后实现Target接口
* 那我们看一下
* Adaptee他来实现Target他的接口
* 并且它是Adaptee的子类
* 那很简单
* 我们这里只需要调用父类的adapteeRequest即可
* 这样我们就通过Adapter把适配者adapteeRequest这个方法呢适配给了Target
* 因为Adapter是Adaptee的子类
* 通过调用父类的adapteeRequest方法
* 来实现了Target
* 那我们看一下
* 类图
*
* 这里面强调的是继承
* 通过继承来获取被适配者的一些方法
* 我们在实现Target的request方法中
* 我们可以增加各种逻辑代码
* 这个还是比较好理解的
* 那我们现在就换一种模式
* 使用对象适配器模式
*
*
* @author Leon.Sun
*
*/
public class Adapter extends Adaptee implements Target{
@Override
public void request() {
//...
super.adapteeRequest();
//...
}
}
package com.learn.design.pattern.structural.adapter.classadapter;
/**
*
* @author Leon.Sun
*
*/
public class Test {
public static void main(String[] args) {
/**
* 我们先写一个具体的Target实现类
* new一个ConcreteTarget这个类
* 这个类在这里就是为了衬托Adapter
* 没有他也是OK的
* 但是ConcreteTarget它是Target的直接实现者
* 现在我们就通过Adapter就把这个实现交给Adaptee
*
*
*/
Target target = new ConcreteTarget();
/**
* 然后调用target的request方法
* 这就是一个Target的实现
*
* 上面是具体的目标的方法
* 也就是Target的具体实现
*
*
*/
target.request();
/**
* 命名一个adapterTarget
* 实现就通过Adapter来实现了
* 因为Adapter实现了Adaptee接口
* 这个时候调用它的request方法
* 通过Adapter已经提交给了Adaptee
* 那这个是类适配器模式
*
*
*
*
*/
Target adapterTarget = new Adapter();
adapterTarget.request();
}
}
client的Test就不看了,主要是看这四个类,注意这里是一个组合,第一个Adapter里面有一个Adaptee,他们两都作为
Target的实现类,那在对比一下刚刚的UML,Target还是有两个实现类,只不过Adapter和Adaptee之间,并不是通过组合关系,
而是通过继承关系,那这个就是类适配器模式,和对象适配器模式最终要的区别,那这两个例子讲完了,现在我们再引入一个
生活场景,那我们现在引入一个生活场景,例如我们手机充电,那在中国民用电都是220V的交流电,那我们手机基本上都是
锂电池,然后需要5V的直流电,那我们买手机的时候呢,会带电源适配器,他的作用是把220V的交流电呢转化成5V的直流电,
那如果不转换呢,手机也就坏了,那那我们现在就使用对象适配器模式,来解决这一个生活场景,那为什么使用对象适配器模式呢,
那在继承和组合的时候呢,我们优先选择组合,这个是前面讲原则的时候有讲过的一个原则,当然呢如果没得选,只能通过继承,
那也没有办法,那我们被适配者肯定是220V,AC代表交流电
package com.learn.design.pattern.structural.adapter.objectadapter;
/**
* 首先还是Target这个接口
* 这个接口不变
*
*
* @author Leon.Sun
*
*/
public interface Target {
void request();
}
package com.learn.design.pattern.structural.adapter.objectadapter;
/**
* 也就是说换模式的时候
* 从类适配器模式
* 到对象适配器模式
* 被适配者和Target
* 是没有变化的
* 那具体的原有的Target
* 实现类也没有变
*
*
* @author Leon.Sun
*
*/
public class Adaptee {
public void adapteeRequest(){
System.out.println("被适配者的方法");
}
}
package com.learn.design.pattern.structural.adapter.objectadapter;
/**
*
* @author Leon.Sun
*
*/
public class ConcreteTarget implements Target {
@Override
public void request() {
System.out.println("concreteTarget目标方法");
}
}
package com.learn.design.pattern.structural.adapter.objectadapter;
/**
* 变化的出现在Adapter上
* 我们创建一个Adapter
* 这里让他直接来实现Target
* 然后实现这个方法
* 因为没有继承
* 所以不能调用父类的方法
* 所以我把Adaptee组合到Adapter这个类里面
* 然后调用它的adapteeRequest
*
* 通过组合的方式
* 把具体实现Target的方法
* 委托给adaptee来实现
* 同样的我们这里可以加代码
* 我们在看一下这个类图
*
*
* @author Leon.Sun
*
*/
public class Adapter implements Target{
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
//...
adaptee.adapteeRequest();
//...
}
}
package com.learn.design.pattern.structural.adapter.objectadapter;
/**
* 我们在copy代码做版本演进的时候
* 一定要注意import里面的包名
* 你们可以直接在源代码上改
* 我这里是为了演示演进的过程
* 以及给适配器模式这两种方式
* 方便你们学习
* Test的代码是没有任何变化的
* 变化的只有一个Adapter
*
*
* @author Leon.Sun
*
*/
public class Test {
public static void main(String[] args) {
Target target = new ConcreteTarget();
target.request();
Target adapterTarget = new Adapter();
adapterTarget.request();
}
}
package com.learn.design.pattern.structural.adapter;
/**
*
* @author Leon.Sun
*
*/
public class AC220 {
/**
* 返回值是int
* 输出220V的交流电
*
*
* @return
*/
public int outputAC220V(){
int output = 220;
System.out.println("输出交流电"+output+"V");
return output;
}
}
package com.learn.design.pattern.structural.adapter;
/**
* 他的方法就是输出5V的直流电
* 那这个就是Target
* 那现在我们写一个适配者
* PowerAdapter
* 电源适配器
*
*
* @author Leon.Sun
*
*/
public interface DC5 {
int outputDC5V();
}
package com.learn.design.pattern.structural.adapter;
/**
* 由他来实现5V的直流电
* 首先在这个适配器的输入呢
* 现在就通过电源适配器里面还有一个变压器
* 实现了220V的交流电转化成5V的直流电
* 那我们测试一下
*
*
* @author Leon.Sun
*
*/
public class PowerAdapter implements DC5{
/**
* 把220V的交流电组合进来
*
*
*/
private AC220 ac220 = new AC220();
/**
* 实现这个方法
*
*
*/
@Override
public int outputDC5V() {
/**
* 赋值220V的交流电
* 输出200V交流电赋值给adapterInput
*
*
*/
int adapterInput = ac220.outputAC220V();
//变压器...
/**
* 输出等于什么呢
* 等于输入进来的220V的交流电除以44
* 具体交流电和直流电怎么变化的呢
* 我们就认为这里是一个变压器
* 也就是说我们适配层的逻辑可以写在这里了
* 这里就比较简单的
* 只把数字除以44
* 变成5
*
*
*/
int adapterOutput = adapterInput/44;
/**
* 然后输出
* 使用电源适配器输入AC
* AC多少呢
* adapterOutput
* 单位
* 加上输出
* 输出直流电DC
* adapterOutput
* 然后加上符号
*
*
*/
System.out.println("使用PowerAdapter输入AC:"+adapterInput+"V"+"输出DC:"+adapterOutput+"V");
/**
* 这个时候把adapterOutput返回回去
*
*
*/
return adapterOutput;
}
}
package com.learn.design.pattern.structural.adapter;
/**
*
* @author Leon.Sun
*
*/
public class Test {
public static void main(String[] args) {
/**
* 首先目标new一个PowerAdapter
*
*
*/
DC5 dc5 = new PowerAdapter();
/**
* 然后直接调用电源适配器的outputDC5V
* 非常简单
* 通过适配器就是这样简单
* 结果已经输出了
* 首先在AC220这个类里面
* 输出了交流电220V
* 然后通过PowerAdapter输出
* 输入是220V的交流电
* 输出是5V的直流电
* 和我们预期是一致的
*
*
*/
dc5.outputDC5V();
}
}