0 设计模式
不了解设计模式的小伙伴可以通过这篇文章了解一下什么是设计模式
https://blog.csdn.net/qq_42874315/article/details/120006447
1 适配器模式
适配器模式又称为包装器和转换器,它与装饰器模式有一些类似,主要的功能是实现接口转换的。
生活中的场景:220V的插头在110V上用不了,这时就需要一个转接头(适配器)。
代码中的场景:Java中想去使用SQLServer,但是Java提供的是JDBC,SQLServer提供的是ODBC,这时在它们之间就需要一个转换器:JDBC-ODBC-Bridge。
2 实现思路
创建一个MediaPlayer 接口和一个实现了MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。
创建高级媒体接口AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。
创建一个适配器让AudioPlayer可以播放其他媒体,MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。
3 需要的类
-
基本实体类的接口 -
高级实体类的接口 要适配的目标 -
高级实体类 实现高级接口 -
转换器 实现基本接口,因为是要将基本转换为高级,所要转换器要实现基本实体类接口,同时需要聚合一个高级实体类 -
基本实体类 实现基本接口,聚合适配器,如果传入的是高级类型的就用适配器去调用 -
测试类
4 具体实现
4.1 MediaPlayer(基本实体类的接口)
/**
* 基本媒体
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:35
*/
public interface MediaPlayer {
void play(String audioType,String fileName);
}
4.2 AdvancedMediaPlayer(高级实体类的接口)
/**
* 高级媒体
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:36
*/
public interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
4.3 高级实体类(实现高级接口)
4.3.1 Mp4Player
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:38
*/
public class Mp4Player implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
4.3.2 VlcPlayer
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:38
*/
public class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
}
}
4.4 MediaAdapter(转换器)
/**
* 基本媒体的适配器
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:40
*/
public class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if("vlc".equalsIgnoreCase(audioType)){
advancedMusicPlayer = new VlcPlayer();
} else if ("mp4".equalsIgnoreCase(audioType)){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if("vlc".equalsIgnoreCase(audioType)){
advancedMusicPlayer.playVlc(fileName);
}else if("mp4".equalsIgnoreCase(audioType)){
advancedMusicPlayer.playMp4(fileName);
}
}
}
4.5 AudioPlayer(基本实体类,原本只支持播放MP3)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:46
*/
public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//播放 mp3 音乐文件的内置支持
if ("mp3".equalsIgnoreCase(audioType)){
System.out.println("Playing mp3 file. Name: "+ fileName);
}else if ("vlc".equalsIgnoreCase(audioType) || "mp4".equalsIgnoreCase(audioType)){
//mediaAdapter 提供了播放其他文件格式的支持
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType,fileName);
}else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
4.6 测试类
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:53
*/
public class Test {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
5 扩展(引入工厂,优化上述实例)
5.1 上述实例中存在的一些问题
- 问题1:AdvancedMediaPlayer中有多种方法,对于不需要的实现类来说,必需得实现,空着放在那儿
- 问题2:AudioPlayer中如果不是基本的mp3,就不用再进行判断了,直接调用适配器,将原来别的mp4、vlc判断交给适配器,这样AudioPlayer的代码就不用再改变了。(如果不这样做的话,后面再加一种mp5,AudioPlayer代码就得改了)
- 问题3:适配器MediaAdapter中,if太多了,应该想办法消灭一些
5.2 解决方案
- 问题1:合并AdvancedMediaPlayer中的playVlc()和playMp4(),使用playAdvanced()代替
- 问题2:AudioPlayer中只留下一个if和一个else,表示基本和高级
- 问题3:修改MediaAdapter的play()中为advancedMusicPlayer.playAdvanced(fileName),将原先的if-else全部去除,MediaAdapter的无参构造中,只保留一个if和一个else,用来判断有没有高级实体类(mp4、vlc),给MediaAdapter中聚合的AdvancedMediaPlayer赋值,采用工厂进行赋值。创建一个生产高级实体类的工厂。
5.3 升级后的实例
5.3.1 未修改:MediaPlayer(基本实体类的接口)
/**
* 基本媒体
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:35
*/
public interface MediaPlayer {
void play(String audioType, String fileName);
}
5.3.2 修改:AdvancedMediaPlayer(高级实体类的接口)
/**
* 高级媒体
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:36
*/
public interface AdvancedMediaPlayer {
void playAdvanced(String fileName);
}
5.3.3 修改:高级实体类(实现高级接口)
Mp4Player
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:38
*/
public class Mp4Player implements AdvancedMediaPlayer {
@Override
public void playAdvanced(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
VlcPlayer
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:38
*/
public class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playAdvanced(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
}
5.3.4 修改:MediaAdapter(转换器)
/**
* 基本媒体的适配器
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:40
*/
public class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
// 判断一下工厂中是否有这个高级类型
if (AdvancedMediaPlayerFactory.advancedMediaFactory.containsKey(audioType)){
advancedMusicPlayer = AdvancedMediaPlayerFactory.advancedMediaFactory.get(audioType);
} else {
System.out.println("Invalid media. " + audioType + " format not supported");
// 真实的场景中,在这里抛出异常,就不会用空的对象去执行play方法了(就不会造成空指针异常了)
System.exit(0);
}
}
@Override
public void play(String audioType, String fileName) {
advancedMusicPlayer.playAdvanced(fileName);
}
}
5.3.5 修改:AudioPlayer(基本实体类,原本只支持播放MP3)
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:46
*/
public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//播放 mp3 音乐文件的内置支持
if ("mp3".equalsIgnoreCase(audioType)){
System.out.println("Playing mp3 file. Name: "+ fileName);
}else {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType,fileName);
}
}
}
5.3.6 新增:创造高级实体类的工厂
/**
* 创造高级实体类的工厂
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 18:25
*/
public class AdvancedMediaPlayerFactory {
public static Map<String,AdvancedMediaPlayer> advancedMediaFactory = new HashMap<>();
public static AdvancedMediaPlayer getAdvancedMediaFactory(String advancedMediaType){
return advancedMediaFactory.get(advancedMediaType);
}
public static void registerAdvancedMedia(String advancedMediaType,AdvancedMediaPlayer advancedMediaPlayer){
// 这里最好先判断一下advancedMediaType和advancedMediaPlayer是否为空或""再进行put
advancedMediaFactory.put(advancedMediaType,advancedMediaPlayer);
}
}
5.3.7 测试类
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/8/21 17:53
*/
public class Test {
public static void main(String[] args) {
// 这里模拟Springboot启动后自动注册高级对象到工厂map的操作
// springboot场景中,可以让AdvancedMediaPlayer接口去继承InitializingBean
// 这样子类都必须要实现一个方法afterPropertiesSet(),这个方法实在程序之后的时候,默认要执行一次的方法,在这里可以进行一下的注册操作
// 详见项目:24-eliminate-if-else 文章:利用设计模式优雅的干掉if-else
AdvancedMediaPlayerFactory.registerAdvancedMedia("mp4",new Mp4Player());
AdvancedMediaPlayerFactory.registerAdvancedMedia("vlc",new VlcPlayer());
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
6 思维导图
7 示例源码地址
https://github.com/ChenJiahao0205/design-pattern/tree/master
最后
我是通过马士兵老师的视频和菜鸟教程学习的,部分内容可能会有雷同
想阅读更多设计模式相关文章,欢迎到我的专栏【设计模式学习笔记】、【设计模式】中去查看
在23篇设计模式文章发布完成之后,我会公开完整的思维导图,点关注,不迷路
感谢大家看到这里,文章如有不足,欢迎大家指出;彦祖点个赞吧彦祖点个赞吧彦祖点个赞吧,欢迎关注程序员五条!
|