适配器模式(AdapterPattern, 结构型模式)
用最通俗的讲法就是: 将多个功能相关或不相关的接口( 你需要的接口 )放到同一个实现类里, 构造一个具有多工功能, 多特点的"异类对象"
-
定义
是作为多个接口之间的桥梁,结合多个独立的接口(将多个类/功能结合在一起,构建出一个可以产生需要的对象的适配器) -
角色关系
多个独立的接口及其实现类, 适配器(实现这多个目标接口) -
优点
可以让多个个没有关系的接口/类一起运行, 提高类的复用性, 增加类的灵活性 -
缺点
过多使用适配器造成系统凌乱, 例如:表面上使用A接口,适配器却将A改为B接口,造成接口使用的混乱, 因此如果不是有必要的, 可以不使用适配器, 而是直接对系统重构
由于java单继承, 当适配类的时候, 只能适配一个类(为抽象类);
注: 适配器主要是用与解决正在服役的项目的问题, 不是在类详细设计的时候添加 (使用适配器, 构造出一个我们想要的对象, 解决燃眉之急)
- 实现方式
一般通过适配器继承或者以来已有对象, 实现想要的目标接口
代码演示:
例1
将播放MP4与VCL的播放器进行适配, 构建一个既能播放MP4, 又能放VCL的播放器
package com.AdapterPattern;
/*** 1、系统需要使用现有的类,而此类的接口不符合系统的需要。* 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。* 3、通过接口转换,将一个类插入另一个类系中。* @author regotto**/
public class AdapterPatternDemo1 {public static void main(String[] args) {AudioPlayer ap=new AudioPlayer();ap.play("mp3", "1号文件");ap.play("vcl", "2号文件");ap.play("mp4", "3号文件");}
}//最高级的播放器
interface MediaPlayer{public void play(String audioType,String fileName);
}//实现MediaPlayer, 可播放mp3, 调用视屏播放的适配器,达到播放mp4, vcl的目的
class AudioPlayer implements MediaPlayer{MediaAdapter ma=null;@Overridepublic void play(String audioType, String fileName) {if(audioType.equals("mp3")) System.out.println("Playing:"+fileName);else if(audioType.equals("vcl") || audioType.equals("mp4")) {ma=new MediaAdapter(audioType);ma.play(audioType, fileName);}else System.out.println("文件格式未识别");}
}//播放器适配器(抽取出相同的特性进行适配), 将vcl mp4的播放进行适配, 得到一个既能放VCL又能放MP4的一个播放器
class MediaAdapter implements MediaPlayer{AdvanceMediaPlayer amp=null;public MediaAdapter(String audioType) {if(audioType.equals("vcl")) {amp=new VlcPlayer();}else if(audioType.equals("mp4")) {amp=new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equals("vcl"))amp.playVlc(fileName);else if(audioType.equals("mp4"))amp.playMp4(fileName);}}//播放VCL, MP4, VCL/MP4通过相同的接口实现,具有一定的共同特征
interface AdvanceMediaPlayer{void playVlc(String fileName);void playMp4(String fileName);
}
class VlcPlayer implements AdvanceMediaPlayer{@Overridepublic void playVlc(String fileName) {System.out.println("Playing: "+ fileName);}@Overridepublic void playMp4(String fileName) {}
}
class Mp4Player implements AdvanceMediaPlayer{@Overridepublic void playMp4(String fileName) {System.out.println("Playing: "+ fileName);}@Overridepublic void playVlc(String fileName) {}
}
例2
使用老虎对象, 与fly接口, 通过适配器构造一个"飞虎对象"
package com.AdapterPattern;public class AdapterPatternDemo2 {public static void main(String[] args) {new AnimalAdapter(new Tiger("Atiger", "东北虎")).fly();}}//飞虎
class AnimalAdapter implements Flying{private Animal animal;public AnimalAdapter(Animal animal) {this.animal = animal;}@Overridepublic void fly() {animal.behavior();System.out.println("I can fly");}
}abstract class Animal{protected String name;protected String animalType;abstract public void behavior();public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAnimalType() {return animalType;}public void setAnimalType(String animalType) {this.animalType = animalType;}}
//老虎
class Tiger extends Animal{public Tiger() {}public Tiger(String name, String animalType) {this.name = name;this.animalType = animalType;}@Overridepublic void behavior() {System.out.println(name+"--"+animalType+"--森林之王");}
}
interface Flying{void fly();
}
//鸟
class Bird extends Animal implements Flying{@Overridepublic void behavior() {System.out.println(name+"--"+animalType);fly();}@Overridepublic void fly() {System.out.println("I can fly");}
}
结语:
适配器就是将多个功能结合在一起, 达到一个新的功能, 与建造者模式不同的是, 适配器实现的接口可以有关系, 也可以没有关系, 建造者模式依赖的是不变的关系, 变的只是内部的零件