适配器这个词我们应该很熟悉,天天都在使用,手机充电时,电源线头头就叫电源适配器,干什么用的呢?把220V电压转换为手机充电时使用的电压,那适配器模式是不是很好理解了,下面看一下定义。
适配器模式(Adapter),将一个类的接口转换成客户希望的另外一个接口。使原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式有“类适配器”和“对象适配器”两种不同的形式。
通过继承进行适配(类间继承)。UML结构图如下:
Target目标角色,该角色定义把其他类转换为何种接口,也就是期望接口,通常情况下是一个接口或一个抽象类,一般不会是实现类。
1 public interface Target { 2 3 public void request(); 4 5 }
Adaptee源角色,想把谁转换为目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象。
1 public class Adaptee { 2 3 public void specificRequest() { 4 System.out.println("特殊请求"); 5 } 6 7 }
Adapter适配器角色,是适配器模式的核心角色,它的职责是通过继承或是类关联的方式把源角色转换为目标角色。
1 public class Adapter extends Adaptee implements Target { 2 3 @Override 4 public void request() { 5 super.specificRequest(); 6 } 7 8 }
目标角色的实现类。
1 public class ConcreteTarget implements Target { 2 3 @Override 4 public void request() { 5 System.out.println("普通请求"); 6 } 7 8 }
1 public class Client { 2 3 public static void main(String[] args) { 4 //原有业务逻辑 5 Target target = new ConcreteTarget(); 6 target.request(); 7 8 //增加适配器后的业务逻辑 9 Target target2 = new Adapter(); 10 target2.request(); 11 } 12 13 }
此时原有业务逻辑输出“普通请求”,增加适配器后的业务逻辑输出“特殊请求”,下同。
通过对象层次的关联关系进行委托(对象的合成关系/关联关系)。UML结构图如下:
客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
1 public class Target { 2 3 public void request() { 4 System.out.println("普通请求"); 5 } 6 7 }
需要适配的类。
1 public class Adaptee { 2 3 public void specificRequest() { 4 System.out.println("特殊请求"); 5 } 6 7 }
通过在内部包装一个Adaptee对象,把源接口转换成目标接口。
1 public class Adapter extends Target { 2 3 private Adaptee adaptee = new Adaptee(); 4 5 @Override 6 public void request() { 7 adaptee.specificRequest(); 8 } 9 }
1 public class Client { 2 3 public static void main(String[] args) { 4 Target target = new Adapter(); 5 target.request(); 6 } 7 8 }
下面我们以翻译官为例,姚明刚去美国时,不懂英文,专门为他配备了翻译,特别是在比赛场上,教练、队员与他的对话全部都通过翻译来沟通,这里翻译就是适配器。现在编写一个适配器模式的例子,火箭队比赛,教练叫暂停时给后卫、中锋、前锋分配进攻和防守任务。UML图如下:
抽象球员类,有进攻和防守两种方法。
1 public abstract class Player { 2 3 protected String name; 4 5 public Player(String name) { 6 this.name = name; 7 } 8 9 public abstract void attack(); //进攻 10 public abstract void defense(); //防守 11 }
这里以前锋为例,其余的就不过多赘述了。重写了Player类中的进攻和防守两个方法,此时是英文的,尚未翻译。
1 public class Forwards extends Player { 2 3 public Forwards(String name) { 4 super(name); 5 } 6 7 @Override 8 public void attack() { 9 System.out.println("Forward " + name + " attack"); 10 } 11 12 @Override 13 public void defense() { 14 System.out.println("Forward " + name + " defense"); 15 } 16 17 }
public class ForeignCenters { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void attackChi() { System.out.println("中锋 " + name + " 进攻"); } public void defenseChi() { System.out.println("中锋 " + name + " 防守"); } }
翻译者类,也就是适配器。对英文的进攻和防守进行翻译。
1 public class Translator extends Player { 2 3 private ForeignCenters foreignCenter = new ForeignCenters(); 4 5 public Translator(String name) { 6 super(name); 7 foreignCenter.setName(name); 8 } 9 10 @Override 11 public void attack() { 12 foreignCenter.attackChi(); 13 } 14 15 @Override 16 public void defense() { 17 foreignCenter.defenseChi(); 18 } 19 20 }
1 public class Client { 2 3 public static void main(String[] args) { 4 Player bPlayer = new Forwards("巴蒂尔"); 5 bPlayer.attack(); 6 7 Player mPlayer = new Guards("麦克格雷迪"); 8 mPlayer.attack(); 9 10 Player yPlayer = new Translator("姚明"); 11 yPlayer.attack(); 12 yPlayer.defense(); 13 } 14 15 }
运行结果如下:
从运行结果可以看到,“attack”和“defense”命令在姚明这里被翻译成了“进攻”和“防守”。
从上面的内容可以看出来,类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。
由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,而类适配器就只能通过覆写源角色的方法进行扩展。
在实际项目中,对象适配器使用到的场景较多。
如对本文有疑问, 点击进行留言回复!!
网友评论