适配器模式(Adapter Pattern)
定义: 适配器允许两个不兼容的接口一起工作.
Definition: An adapter allows two incompatible interfaces to work together.
类型: 结构型
用法:
When?: An adapter can be used when the wrapper must respect(遵循) a particular(特定) interface and must support polymorphic(多态) behavior.
- 当包装器(wrapper)必须遵循特定接口并且必须支持多态行为时,可以使用适配器模式。
- 装饰器模式可以在运行时添加或更改接口的行为
- 在需要更简单或更简单的基础对象接口时使用外观模式。
Pattern |
Intent |
Adapter or Wrapper |
Converts one interface to another so that it matches what the client is expecting |
Decorator |
Dynamically adds responsibility to the interface by wrapping the original code |
Delegation(委派模式) |
Support “composition over inheritance” |
Facade |
Provides a simplified interface |
对象适配器模式(Object adapter pattern)
在此适配器模式中,适配器包含它包装的类的实例。在这种情况下,适配器调用包装对象的实例。
UML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @startuml Object adapter pattern class Adaptee{ + methodB() }
class Adaptor{ + adaptee: Adaptee + methodA() }
class Client{ + adaptor: Adaptor + doWork() }
note bottom of Adaptor ... adpatee.methodB() ... end note
note bottom of Client ... adpator.methodA() ... end note Adaptee --> Adaptor Adaptor <-- Client
@enduml
|
类适配器模式(Class adapter pattern)
此适配器模式使用多个多态接口实现或继承预期的接口和预先存在的接口。通常将期望的接口创建为纯接口类,尤其是在不支持类的多重继承的Java(JDK 1.8之前)等语言中。
UML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @startuml class Adaptee1{ + method1() } class AdapteeN{ + method2() }
class Adaptor{ + methodA() }
class Client{ + adaptor: Adaptor + doWork() }
Client --> Adaptor Adaptor --|> Adaptee1 Adaptor --|> AdapteeN
note right of Adaptor ... adpatee.methodB() ... end note
note right of Client ... adpatee.methodB() ... end note
@enduml
|
适配器模式实例
UML
适配器接口
1 2 3 4 5 6 7 8 9 10 11
| public interface MediaPlayer { void play(String audioType, String fileName); }
public interface AdvancedMediaPlayer { void playVlc(String fileName);
void playMp4(String fileName); }
|
AdvancedMediaPlayer支持的具体类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class VlcPlayer implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { System.out.println("Playing vlc file. file name: "+ fileName); }
@Override public void playMp4(String fileName) { } }
public class Mp4Player implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { }
@Override public void playMp4(String fileName) { System.out.println("Playing mp4 file. file name: "+ fileName); } }
|
润滑油(适配器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMediaPlayer;
public MediaAdapter(String audioType) { if ("vlc".equalsIgnoreCase(audioType)) { advancedMediaPlayer = new VlcPlayer(); } else if ("mp4".equalsIgnoreCase(audioType)) { advancedMediaPlayer = new Mp4Player(); } }
@Override public void play(String audioType, String fileName) { if(audioType.equalsIgnoreCase("vlc")){ advancedMediaPlayer.playVlc(fileName); } else if(audioType.equalsIgnoreCase("mp4")){ advancedMediaPlayer.playMp4(fileName); } } }
|
具体调用类(自生产品功能类)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override public void play(String audioType, String fileName) {
if ("mp3".equalsIgnoreCase(audioType)){ System.out.println("Playing mp3 file. file name: "+ fileName); }
else if ("vlc".equalsIgnoreCase(audioType)|| "mp4".equalsIgnoreCase(audioType)){ mediaAdapter = new MediaAdapter(audioType); mediaAdapter.play(audioType,fileName); } else { System.out.println("Invalid media. " + audioType + " format not supported"); } } }
|
使用场景
1 2 3 4 5 6 7 8 9
| public class AdapterPatternDemo { public static void main(String[] args) { AudioPlayer audioPlayer = new AudioPlayer(); audioPlayer.play("mp3","hello.mp3"); audioPlayer.play("mp4","hello.mp4"); audioPlayer.play("vlc","hello.vlc"); audioPlayer.play("avi","hello.avi"); } }
|
Adapter Pattern的优缺点
优点:
- 可以让任何两个没有关联的类一起运行
- 提高了类的复用
- 增加了类的透明度
缺点:
- 过度使用会造成系统混乱零散
- 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类