哪个网站专门做母婴,做电影网站 需要进那些群,静海做网站公司,wordpress widget hook前言
作者在准备秋招中#xff0c;学习设计模式#xff0c;做点小笔记#xff0c;用宝可梦为场景举例#xff0c;有错误欢迎指出。
适配器模式
意图#xff1a;将一个类的接口转换成客户希望的另一个接口
主要解决#xff1a;把现有对象放到新环境里#xff0c;而新…前言
作者在准备秋招中学习设计模式做点小笔记用宝可梦为场景举例有错误欢迎指出。
适配器模式
意图将一个类的接口转换成客户希望的另一个接口
主要解决把现有对象放到新环境里而新环境要求的接口现有对象不满足
何时使用现有的类被需要而这个类的接口不符合要求建立一个可复用的类用于让彼此之间无关的类或未来可能引入的类可以一起工作
适配器模式有3个角色
目标接口 Target当前系统业务期待的接口适配者类被适配的现有组件的接口适配器类一个转换器继承或引用适配者对象把适配者接口转为目标接口
1 情景假设
现在我们假设这样一个场景小智在绿宝石的存档中有一只巨tm强的裂空座性格好个体高努力值也刷得完美。现在已经发售了朱紫他还想用这只裂空座但是问题来了绿宝石是GBA主机的游戏朱紫是Switch主机的游戏他们存储数据的格式不同啊这怎么办呢那么就只能推出一个适配器把GBA的数据转化成Switch的数据把裂空座从绿宝石移植到朱紫可能熟悉宝可梦游戏的朋友已经想到了Pokemon Home就是干这个事的所以我们可以把这个故事中的角色抽象为适配器模式需要的三个角色
目标接口Switch数据适配者类GBA数据适配器类Pokemon Home 2 代码示例 现有的接口就是老版本GBA游戏
public interface GbaGame {void usePokemon(String dataFormat);
}public class EmeraldVersion implements GbaGame{/*** 在绿宝石中使用宝可梦*/public void usePokemon(String dataFormat, String version) {System.out.println(Go! Rayquaza! (In version Version));}public void usePokemon() {System.out.println(Go! Rayquaza! (In GBA Version ));}
}有绿宝石一个实现类然而现在游戏已经到了朱紫版本需要的是Switch上的数据
public interface NsGame{void usePokemon(String dataFormat);
}public class ScarletVersion implements NsGame{public void usePokemon(String dataFormat){if (nsData.equals(dataFormat)){// 内置功能使用当前版本的宝可梦System.out.println(Go! Chikorita (Get In Scarlet Version));}}
}于是为了让NS端适配GBA的数据我们需要一个适配器这个适配器要有旧版本的属性因为适配器是为已有的类设计的
/*** Pokemon Home*/
public class DataAdapter implements GbaGame{GbaGame gbaGame; // 旧世代public DataAdapter(GbaGame gbaGame) {this.gbaGame gbaGame;}Overridepublic void usePokemon(String dataFormat) {if(gbaData.equals(dataFormat)){gbaGame.usePokemon(dataFormat);}}
}所以要在新版本NsGame中使用旧版本的数据新版本应该是
public class ScarletVersion implements NsGame{DataAdapter dataAdapter;public void usePokemon(String dataFormat){if (gbaData.equals(dataFormat)){dataAdapter new DataAdapter(new EmeraldVersion());dataAdapter.usePokemon(dataFormat, Switch);}else if (nsData.equals(dataFormat)){// 内置功能使用当前版本的宝可梦System.out.println(Go! Chikorita (Get In Scarlet Version));}}
}注意这里并不违背“开闭原则”因为前面的ScarletVersion类只是为了说明逻辑并不是对代码进行修改
测试类
public class AdapterDemo {public static void main(String[] args) {// 老版本使用EmeraldVersion emeraldVersion new EmeraldVersion();emeraldVersion.usePokemon();// 新版本使用NsGame pokemon new ScarletVersion();pokemon.usePokemon(gbaData);pokemon.usePokemon(nsData);}
}Go! Rayquaza! (In GBA Version )
Go! Rayquaza! (In Switch Version)
Go! Chikorita (Get In Scarlet Version)3 扩展
有聪明的读者就会问了那既然有开闭原则那如果有新的旧版本或者新版本要加入怎么办呢
旧版本增加比如我想把3DS上的宝可梦拿到朱紫用要怎么办
如果无视开闭原则可以这样修改但其实这种情况更适用于一开始就告诉了开发者要适配2个旧版本。
public class DataAdapter implements GbaGame, ThreeDS{GbaGame gbaGame; // 旧世代ThreeDS threeDS; // 3DS世代游戏public DataAdapter(GbaGame gbaGame, ThreeDS threeDS) {this.gbaGame gbaGame;this.threeDS threeDS;}Overridepublic void usePokemon(String dataFormat, String newVersion) {if(gbaData.equals(dataFormat)){gbaGame.usePokemon(dataFormat, newVersion);}else if(threeDS.equals(dataFormat)){threeDS.usePokemon(dataFormat, newVersion);}}
}所以正确的做法是为ThreeDS单独再写一个适配器类
public ThreeDsAdapter implements ThreeDS{//...
}目标接口的新实现比如剑盾版本也是NS端的和朱紫写一样的逻辑即可
3 另一个例子
题外话在学习这个设计模式的时候想到的在做机器学习的时候通常有这么个流程
数据集 - 数据源 - 模型 - …
数据集的格式各不相同然而模型的输入是固定的我们把数据集转换成能够进入模型的过程通常被叫做数据预处理这是为了让数据集和模型输入的格式适配。比如 每个数据集的分割符不同那么为了提供给模型一个模型能够接受的格式就可以使用适配器模式让数据从csv或者dat格式转换为data_df即dataframe对象的过程也就是适配的过程。