(4).对象适配器模式
实现方式: 对象适配器模式可采用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。
目标接口(中国)
package com.jsxs.structure.adapter.class_adapter; /** * @Author Jsxs * @Date 2023/4/20 18:47 * @PackageName:com.jsxs.structure.adapter.class_adapter * @ClassName: SDScard * @Description: TODO 目标接口 (SD卡) * @Version 1.0 */ public interface SDCard { // 从SD卡中读取数据 String readSD(); //往SD卡中写数据 void writeSD(String msg); }
package com.jsxs.structure.adapter.class_adapter; /** * @Author Jsxs * @Date 2023/4/20 18:49 * @PackageName:com.jsxs.structure.adapter.class_adapter * @ClassName: SDCardIml * @Description: TODO * @Version 1.0 */ public class SDCardIml implements SDCard{ @Override public String readSD() { String msg="SDCard red msg : hello word"; return msg; } @Override public void writeSD(String msg) { System.out.println("SDCard write msg:"+msg); } }
适配者类()欧洲
package com.jsxs.structure.adapter.class_adapter; /** * @Author Jsxs * @Date 2023/4/20 18:42 * @PackageName:com.jsxs.structure.adapter.class_adapter * @ClassName: TFCard * @Description: TODO 适配者类的接口 * @Version 1.0 */ public interface TFCard { // 从TF卡中读取数据 String readTF(); // 网TF卡中写数据 void writeTF(String msg); }
package com.jsxs.structure.adapter.class_adapter; /** * @Author Jsxs * @Date 2023/4/20 18:44 * @PackageName:com.jsxs.structure.adapter.class_adapter * @ClassName: TFCardImi * @Description: TODO 适配者类 * @Version 1.0 */ public class TFCardImi implements TFCard{ @Override public String readTF() { String msg="TFCARD READ MSG: HELLO WORLD"; return msg; } @Override public void writeTF(String msg) { System.out.println("TFCARD WRITE MSG:"+msg); } }
计算机类
package com.jsxs.structure.adapter.class_adapter; /** * @Author Jsxs * @Date 2023/4/20 18:54 * @PackageName:com.jsxs.structure.adapter.class_adapter * @ClassName: Computer * @Description: TODO 计算机类 * @Version 1.0 */ public class Computer { // 从SD卡中读取数据 public String readSD(SDCard sdCard){ if (sdCard==null){ throw new RuntimeException("SDCard is not null"); } return sdCard.readSD(); } }
这里修改成聚合
package com.jsxs.structure.adapter.object_adpater; /** * @Author Jsxs * @Date 2023/4/20 18:59 * @PackageName:com.jsxs.structure.adapter.class_adapter * @ClassName: SDAdapterTF * @Description: TODO 适配器类 (转换器) * @Version 1.0 */ public class SDAdapterTF implements SDCard { //实现当前业务的接口、同时继承已经存在的的组件。 // 聚合适配者类 private TFCard tfCard; // 设置有参构造方法,目的是使用哪个实现类 public SDAdapterTF(TFCard tfCard) { this.tfCard = tfCard; } @Override public String readSD() { return tfCard.readTF(); } @Override public void writeSD(String msg) { tfCard.writeTF(msg); } }
package com.jsxs.structure.adapter.object_adpater; /** * @Author Jsxs * @Date 2023/4/20 18:56 * @PackageName:com.jsxs.structure.adapter.class_adapter * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { // 创建计算机对象 Computer computer = new Computer(); //读取SD卡中的数据 String s = computer.readSD(new SDCardIml()); System.out.println(s); System.out.println("--------------------------"); // 使用该计算机读取TF卡中的数据 // 定义适配器类 SDAdapterTF sdAdapterTF = new SDAdapterTF(new TFCardImi()); String s1 = sdAdapterTF.readSD(); System.out.println(s1); } }
以上的方法实现了接口复用。聚合
注意: 还有一个适配器模式是接口适配器模式。当不希望实现一个接口中的所有方法,可以抽像一个Adapter,实现所有方法。而我们只需要继承该抽象类即可。
(5).应用场景
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同
(6).JDK源码解析
Reader
(字符流)、InputStream
(字节流)的适配使用的是InputStreamReader。
InputStreamReader继承自Java.io包中的Reader,对其中的抽象方法给出了实践。
3.桥接模式
(1).概述
现在有一个需求,需要创建不同的图形,并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系。
我们可以发现有很多的类,假如我们再增加一种颜色或一个形状,就需要创建更多的类。
试想,在一个多种可能会变化的维度的系统中,用继承方式会造成类爆炸
,扩展起来不灵活。每次在一个维度上新增一个具体实现都要增加多个子类,为了更加灵活的设计系统,我们此时可以考虑使用桥接模式。
定义
:
将抽象与实现分离,使他们可以独立变化。他是用组合关系代理继承关系来实现,从而降低了抽象和实现这两个可唯独的耦合度
。
(2).结构
桥接模式包含以下角色:
抽象化角色
: 定义抽象类,并包含一个对实现话对象的引用扩展抽象化角色
: 是抽象化角色的子类,实现父类
中的业务方法,并通过组合关系调用实现化角色中的业务方法。实现化角色
: 定义实现化角色的接口,供扩展抽象化角色调用具体实现化角色
: 给出实现化角色接口的具体实现。
(3).案列
eg: 视频播放器
需要开发一个跨平台视频播放器,可以在不同操作系统平台(如windows,mac,Linux等)上播放多种格式的视频文件,常见的视频格式包括RMVB、AVI、WMV等。该播放器包含两个维度,适合使用桥接模式。
实现化角色
package com.jsxs.structure.Bride; /** * @Author Jsxs * @Date 2023/4/21 20:43 * @PackageName:com.jsxs.structure * @ClassName: Bride * @Description: TODO 实现化角色 * @Version 1.0 */ public interface VideoFile { // 解码 void decode(String fileName); }
具体的实现化角色
package com.jsxs.structure.Bride; /** * @Author Jsxs * @Date 2023/4/21 20:44 * @PackageName:com.jsxs.structure.Bride * @ClassName: AVI * @Description: TODO 具体的实现化角色 * @Version 1.0 */ public class AVI implements VideoFile{ @Override public void decode(String fileName) { System.out.println("AVI视频文件:"+fileName); } }
package com.jsxs.structure.Bride; /** * @Author Jsxs * @Date 2023/4/21 20:45 * @PackageName:com.jsxs.structure.Bride * @ClassName: MP4 * @Description: TODO 具体的实现化角色 * @Version 1.0 */ public class MP4 implements VideoFile{ @Override public void decode(String fileName) { System.out.println("MP4:"+fileName); } }
抽象化角色
package com.jsxs.structure.Bride; /** * @Author Jsxs * @Date 2023/4/21 20:46 * @PackageName:com.jsxs.structure.Bride * @ClassName: OS * @Description: TODO 抽象化角色 * @Version 1.0 */ public abstract class OS { // 聚合: 设置的类型为保护类型目的是为了让子类访问。 protected VideoFile videoFile; // 因为我们设置有参构造函数,所以子类必须要赋值 public OS(VideoFile videoFile) { this.videoFile = videoFile; } public abstract void play(String fileName); }
扩展抽象化角色
package com.jsxs.structure.Bride; /** * @Author Jsxs * @Date 2023/4/21 21:00 * @PackageName:com.jsxs.structure.Bride * @ClassName: Windows * @Description: TODO 扩展抽象化角色 * @Version 1.0 */ public class Windows extends OS{ public Windows(VideoFile videoFile) { super(videoFile); } @Override public void play(String fileName) { videoFile.decode(fileName); } }
package com.jsxs.structure.Bride; /** * @Author Jsxs * @Date 2023/4/21 21:03 * @PackageName:com.jsxs.structure.Bride * @ClassName: Mac * @Description: TODO 扩展抽象化角色 * @Version 1.0 */ public class Mac extends OS{ public Mac(VideoFile videoFile) { super(videoFile); } @Override public void play(String fileName) { videoFile.decode(fileName); } }
package com.jsxs.structure.Bride; /** * @Author Jsxs * @Date 2023/4/21 21:04 * @PackageName:com.jsxs.structure.Bride * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { // 创建Mac系统对象 OS mac = new Mac(new AVI()); // 使用操作系统播放文件 mac.play("战狼4"); } }
好处:
- 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要改变原有维度。如:“如果现在有一种视频wmv,我们只需要再定以一个类实现VideoFile接口即可,其他类不需要在变化”
- 实现细节对客户透明
(4).使用场景
- 当一个类存在两个独立的维度的时候,且这两个维度都需要进行扩展时。
- 当一个系统不希望使用继承或因为多层次导致系统类的个数急剧增加。
- 当一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性时,避免在两个层次之间建立静态的继承连接,通过桥接模式可以使他门在抽象层建立一个关联关系。