组合模式应用-适配器模式_适配器组件
myzbx 2025-09-01 09:54 40 浏览
写在前面
Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!
该部分为各模式组合使用,涉及代码较多,熟能生巧。
内容回顾
定义
适配器模式是一种结构型设计模式,它允许接口不兼容的类能够相互合作。
适配器模式通过创建一个中间层(适配器)来连接两个不兼容的接口,使得原本由于接口不匹配而不能一起工作的类可以协同工作。
它的主要目的是将一个类的接口转换成客户期望的另一个接口,从而解决接口不匹配的问题从而实现代码的复用。
核心思想
- 转化: 将一个类的接口转化成客户期望的另一个接口,使得客户端可以透明的使用被适配者。
- 桥接: 在不修改现有代码(特别是被适配者代码)的情况下,使不兼容的接口能够协同工作,这对集成第三方库、遗留系统或未来可能变化的接口尤为重要。
实现方案
类适配器模式
- 实现方式: 类适配器通过继承被适配者类,同时实现目标接口来完成适配。适配器类既是被适配者,又是目标接口的实现者。
- 优点: 实现简单,直接继承被适配者的功能。
- 缺点:
- 由于Java单继承的限制,适配器类只能继承一个被适配者类,这限制了其灵活性。
- 适配器与被适配者之间的耦合度较高,当被适配者发生变化时,适配器也可能需要修改。
- 无法适配被适配者的子类。
- 适用场景: 当被适配者是一个类,且不需要适配其子类时。
对象适配器模式
- 实现方式: 对象适配器通过组合(持有引用)被适配者对象,并实现目标接口来完成适配。适配器类将客户端的请求委派给内部持有的被适配者对象。
- 优点:
- 适配器可以与任何实现了被适配者接口的类一起工作,也可以适配被适配者的子类。
- 适配器与被适配者之间的耦合度较低,被适配者的变化对适配器的影响较小。
- 一个适配器可以适配多个被适配者(通过组合多个被适配者对象)。
- 缺点: 与类适配器稍微复杂一些,需要额外的对象引用。
- 适用场景: 场景适用较多,特别是当被适配者是接口或抽象类时,或者需要适配多个被适配者时。
使用时机
- 接口不兼容: 最核心的触发条件,当适用某个现有类或第三方库,但其接口与你当前系统期望的接口不匹配时
- 遗留系统集成: 在企业级应用中,新系统往往需要与历史悠久的遗留系统进行交互,遗留系统通常有独特的数据格式和接口,适配器模式可以作为新旧系统之间的桥梁,实现平滑过渡和数据转换。
- 统一接口: 当有多个功能相似但接口不同的类时,可以使用适配器模式为它们提供一个统一的接口,方便客户端调用。
模式组合的应用
适配器模式回顾
假设有一个旧的多媒体播放器系统,最初的设计是为了播放MP3格式的音频文件。现在,随着技术的发展和用户需求的变化,我们需要扩展这个播放器 使其能够播放MP4视频文件和VLC视频文件,而又不想修改现有MP3播放器的代码。采用适配器模式解决该问题。
MediaPlayer(目标接口)
public interface MediaPlayer {
/**
* 播放媒体文件的方法
*
* @param audioType 媒体类型
* @param fileName 文件名
*/
void play(String audioType, String fileName);
}
Mp4Player(被适配者)
public class Mp4Player {
/**
* 播放MP4文件的方法
* <p>
* 此方法名和参数与 MediaPlayer 接口不兼容。
*
* @param fileName
*/
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: " + fileName);
}
}
VlcPlayer(被适配者)
public class VlcPlayer {
/**
* 播放 vlc 文件的方法
* <p>
* 此方法名和参数与 MediaPlayer 接口不兼容
*
* @param fileName VLC文件名
*/
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: " + fileName);
}
}
MediaAdapter(适配器类)
public class MediaAdapter implements MediaPlayer {
/**
* 持有被适配者对象的引用
*/
private Mp4Player mp4Player;
/**
* 持有被适配者对象的引用
*/
private VlcPlayer vlcPlayer;
/**
* 构造函数,根据媒体类型初始化响应的播放器
*
* @param audioType 媒体类型
*/
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("mp4")) {
mp4Player = new Mp4Player();
}
else if (audioType.equalsIgnoreCase("vlc")) {
vlcPlayer = new VlcPlayer();
}
}
@Override
public void play(String audioType, String fileName) {
// 根据媒体类型,调用相应被适配者的播放方法
if (audioType.equalsIgnoreCase("mp4")) {
mp4Player.playMp4(fileName);
}
else if (audioType.equalsIgnoreCase("vlc")) {
vlcPlayer.playVlc(fileName);
}
else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
AudioPlayer(原始播放器)
public class AudioPlayer implements MediaPlayer {
/**
* 适配器类引用
*/
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
}
// mediaAdapter提供了播放其他文件格式的支持
else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
测试类
@Test
public void test_player() {
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");
}
执行结果
Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported
Process finished with exit code 0
- 以上为复习适配者模式的使用加深记忆
适配器模式+工厂模式
在多媒体播放器示例中, AudioPlayer 在需要播放 VLC 或者 MP4 文件时,直接在 play 方法中通过 new MediaAdapter(audioType)的方式创建 MediaAdapter 实例,如果未来需要支持更多媒体类型,AudioPlayer 的 play 方法中的条件判断逻辑会变得越来越复杂和臃肿。通过引入工厂模式,可以将适配器的创建逻辑集中管理,使得 AudioPlayer 无需关心适配器的具体创建过程。
MediaAdapterFactory(多媒体适配器工厂)
public interface MediaAdapterFactory {
MediaPlayer createAdapter(String audioType);
}
ConcreteMediaAdapterFactory(具体工厂类)
public class ConcreteMediaAdapterFactory implements MediaAdapterFactory {
@Override
public MediaPlayer createAdapter(String audioType) {
if (audioType.equalsIgnoreCase("mp4") || audioType.equalsIgnoreCase("vlc")) {
return new MediaAdapter(audioType);
}
return null;
}
}
AudioPlayer(原接口)
public class AudioPlayer implements MediaPlayer {
private MediaAdapterFactory adapterFactory;
/**
* 构造函数 初始化 适配器工厂类
*
* @param adapterFactory
*/
public AudioPlayer(MediaAdapterFactory adapterFactory) {
this.adapterFactory = adapterFactory;
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
}
else {
MediaPlayer adapter = adapterFactory.createAdapter(audioType);
if (adapter != null) {
adapter.play(audioType, fileName);
}
else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
}
- 在 AudioPlayer 中添加对工厂的引用,修改判断逻辑,直接通过工厂方法获取适配器类。
测试类
@Test
public void test_player() {
MediaAdapterFactory factory = new ConcreteMediaAdapterFactory();
AudioPlayer audioPlayer = new AudioPlayer(factory);
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");
}
执行结果
Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported
Process finished with exit code 0
适配器模式+桥接模式
假设我们需要开发一个电商支付系统,需要支持多种支付方式(信用卡、支付宝、微信等), 同时这些支付方式可能有不同的接口版本(如 支付宝有新版和旧版API等)
组合思想
- 桥接模式旨在将抽象与实现分离,使得它们可以独立变化。
- 适配器模式则用于解决接口不兼容的问题。
- 当桥接模式的抽象层需要与一个不兼容的实现层进行交互时,适配器模式可以作为桥梁,将不兼容的实现层适配到桥接模式所期望的接口。
旧版本API
/**
* 旧版微信支付接口
* <p>
* 与 PaymentProcessor 不兼容
*/
public interface LegacyWeChatPay {
boolean pay(double amount, String openId);
boolean cancelPayment(String paymentNo);
}
/**
* 旧版微信支付实现类
*/
public class LegacyWeChatPayImpl implements LegacyWeChatPay {
@Override
public boolean pay(double amount, String openId) {
System.out.println(String.format("旧版微信支付: 金额 %.2f, OpenID %s\n", amount, openId));
return true;
}
@Override
public boolean cancelPayment(String paymentNo) {
System.out.println(String.format("旧版微信支付取消: 支付单号 %s\n", paymentNo));
return true;
}
}
PaymentProcessor
public interface PaymentProcessor {
boolean processPayment(double amount, Map<String, String> paymentDetails);
boolean refund(double amount, String transactionId);
}
- PaymentProcessor 为桥接实现部分,定义支付处理通用接口。
实现部分具体实现类
public class AliPayProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount, Map<String, String> paymentDetails) {
System.out.println(
String.format("支付宝支付: 金额 %.2f, 支付宝账号 %s\n",
amount, paymentDetails.get("aliPayAccount"))
);
return true;
}
@Override
public boolean refund(double amount, String transactionId) {
System.out.println(String.format("支付宝退款: 金额 %.2f, 交易ID %s\n", amount, transactionId));
return true;
}
}
public class CreditCardProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount, Map<String, String> paymentDetails) {
System.out.println(String.format("信用卡支付: 金额 %.2f, 卡号 %s, 有效期 %s\n",
amount, paymentDetails.get("cardNumber"), paymentDetails.get("expiryDate")));
return true;
}
@Override
public boolean refund(double amount, String transactionId) {
System.out.println(String.format("信用卡退款: 金额 %.2f, 支付宝账号 %s \n", amount, transactionId));
return true;
}
}
- 实现部分具体实现类,包含 AliPayProcessor、CreditCardProcessor,定义各自具体支付逻辑。
Payment
public abstract class Payment {
/**
* 接口部分的引用
*/
protected PaymentProcessor paymentProcessor;
protected Payment(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public abstract boolean makePayment(double amount);
public abstract boolean requestRefund(double amount);
public String getTransactionId() {
return "TXN_" + System.currentTimeMillis();
}
}
- Payment 支付抽象类,桥接模式的抽象部分
抽象具体部分具体实现类
/**
* 支付宝支付
* <p>
* 抽象子类
*/
public class AliPayPayment extends Payment {
private String aliPayAccount;
public AliPayPayment(PaymentProcessor paymentProcessor, String aliPayAccount) {
super(paymentProcessor);
this.aliPayAccount = aliPayAccount;
}
@Override
public boolean makePayment(double amount) {
Map<String, String> details = new HashMap<>();
details.put("aliPayAccount", aliPayAccount);
return paymentProcessor.processPayment(amount, details);
}
@Override
public boolean requestRefund(double amount) {
return paymentProcessor.refund(amount, super.getTransactionId());
}
}
/**
* 信用卡支付
* <p>
* 抽象子类
*/
public class CreditCardPayment extends Payment {
private String cardNumber;
private String expiryDate;
private String cvv;
public CreditCardPayment(PaymentProcessor paymentProcessor, String cardNumber, String expiryDate, String cvv) {
super(paymentProcessor);
this.cardNumber = cardNumber;
this.expiryDate = expiryDate;
this.cvv = cvv;
}
@Override
public boolean makePayment(double amount) {
Map<String, String> details = new HashMap<>();
details.put("cardNumber", cardNumber);
details.put("expiryDate", expiryDate);
details.put("cvv", cvv);
return paymentProcessor.processPayment(amount, details);
}
@Override
public boolean requestRefund(double amount) {
return paymentProcessor.refund(amount, super.getTransactionId());
}
}
WeChatPayAdapter
/**
* 适配器类
* <p>
* 将 LegacyWeChatPay 适配道 PaymentProcessor 接口
*/
public class WeChatPayAdapter implements PaymentProcessor {
/**
* 原支付接口的引用
*/
private LegacyWeChatPay legacyWeChatPay;
public WeChatPayAdapter(LegacyWeChatPay legacyWeChatPay) {
this.legacyWeChatPay = legacyWeChatPay;
}
@Override
public boolean processPayment(double amount, Map<String, String> paymentDetails) {
return legacyWeChatPay.pay(amount, paymentDetails.get("openId"));
}
@Override
public boolean refund(double amount, String transactionId) {
// 旧版本中,不支持退款,仅支持取消支付。
return legacyWeChatPay.cancelPayment(transactionId);
}
}
- 适配器类,实现了 PaymentProcessor 接口部分,并持有 LegacyWeChatPay 实例的引用,在通用接口中调整数据结构,调用旧版支付。
WeChatPayment
/**
* 微信支付类
* <p>
* 抽象子类
*/
public class WeChatPayment extends Payment {
private String openId;
public WeChatPayment(PaymentProcessor paymentProcessor, String openId) {
super(paymentProcessor);
this.openId = openId;
}
@Override
public boolean makePayment(double amount) {
Map<String, String> details = new HashMap<>();
details.put("openId", openId);
return paymentProcessor.processPayment(amount, details);
}
@Override
public boolean requestRefund(double amount) {
System.out.println("注意: 微信旧版支付只能取消支付,不能部分退款");
return paymentProcessor.refund(amount, getTransactionId());
}
}
- 新增抽象部分实现,用于调用适配器类,执行旧版本支付逻辑。
测试类
@Test
public void test_pay() {
// 创建不同的支付处理器
PaymentProcessor creditCardProcessor = new CreditCardProcessor();
PaymentProcessor aliPayProcessor = new AliPayProcessor();
// 创建旧版微信支付实例和适配器
PaymentProcessor weChatPayAdapter = new WeChatPayAdapter(new LegacyWeChatPayImpl());
Payment creditCardPayment = new CreditCardPayment(creditCardProcessor, "1234-5678-9012-3456", "12/25", "123");
Payment aliPayPayment = new AliPayPayment(aliPayProcessor, "user@alipay.com");
Payment weChatPayment = new WeChatPayment(weChatPayAdapter, "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");
// 支付
System.out.println("--- 支付测试 ---");
creditCardPayment.makePayment(100.0);
aliPayPayment.makePayment(200.0);
weChatPayment.makePayment(150.0);
// 退款
System.out.println("--- 退款测试 ---");
creditCardPayment.requestRefund(50.0);
aliPayPayment.requestRefund(100.0);
weChatPayment.requestRefund(150.0);
// 切换支付处理器
System.out.println("--- 切换支付处理器测试 ---");
Payment creditCardWithAliPayProcessor = new CreditCardPayment(aliPayProcessor, "1234-5678-9012-3456", "12/25", "123");
creditCardWithAliPayProcessor.makePayment(300.0);
}
执行结果
--- 支付测试 ---
信用卡支付: 金额 100.00, 卡号 1234-5678-9012-3456, 有效期 12/25
支付宝支付: 金额 200.00, 支付宝账号 user@alipay.com
旧版微信支付: 金额 150.00, OpenID oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
--- 退款测试 ---
信用卡退款: 金额 50.00, 支付宝账号 TXN_1754707835276
支付宝退款: 金额 100.00, 交易ID TXN_1754707835276
注意: 微信旧版支付只能取消支付,不能部分退款
旧版微信支付取消: 支付单号 TXN_1754707835276
--- 切换支付处理器测试 ---
支付宝支付: 金额 300.00, 支付宝账号 null
Process finished with exit code 0
组合优势
- 添加新的支付方式只需要继承Payment类
- 添加新的支付处理器只需要实现PaymentProcessor接口
- 集成旧系统只需要创建适配器,不影响核心架构
适配器模式+策略模式
依然以支付系统为例,将 适配器模式 与 策略模式组合使用。
代码结构
代码结构
ThirdPartyPayment
public interface ThirdPartyPayment {
void makePayment(double amount, String account);
}
- ThirdPartyPayment 为第三方支付接口,为原始定义接口,现需要适配该接口。
被适配目标类
/**
* 支付宝实现
* <p>
* 需适配的类
*
* @author YiYuan
* @data 2025/8/8
* @apoNote
*/
public class AliPayService implements ThirdPartyPayment {
@Override
public void makePayment(double amount, String account) {
System.out.println(String.format("AliPay payment processed: $%.2f to account %s \n", amount, account));
}
}
/**
* 微信支付
* <p>
* 需适配的类
*
* @author YiYuan
* @data 2025/8/8
* @apoNote
*/
public class WeChatPayService implements ThirdPartyPayment {
@Override
public void makePayment(double amount, String account) {
System.out.println(String.format("WeChatPay payment processed: $%.2f to account %s \n", amount, account));
}
}
UnifiedPayment
/**
* 统一的支付目标接口
* <p>
* 适配器模式的目标接口
*/
public interface UnifiedPayment {
void processPayment(double amount, String paymentDetails);
}
- UnifiedPayment 是支付系统内,新定义的支付接口类,所有支付均需要对该类进行实现,适配目标类
支付系统实现类
/**
* PayPal 支付
*/
public class PayPalPayment implements UnifiedPayment {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public void processPayment(double amount, String paymentDetails) {
System.out.println(String.format("Processing PayPal payment: $%.2f\n", amount));
System.out.println("PayPal account: " + email);
System.out.println("Payment details: " + paymentDetails);
}
}
/**
* 信用卡支付
*/
public class CreditCardPayment implements UnifiedPayment {
private String cardNumber;
private String cardHolder;
public CreditCardPayment(String cardNumber, String cardHolder) {
this.cardNumber = cardNumber;
this.cardHolder = cardHolder;
}
@Override
public void processPayment(double amount, String paymentDetails) {
System.out.println(String.format("Processing credit card payment: $%.2f\n", amount));
System.out.println("Card: " + maskCardNumber(cardNumber) + ", Holder: " + cardHolder);
System.out.println("Payment details: " + paymentDetails);
}
private String maskCardNumber(String cardNumber) {
return "****_****_****_" + cardNumber.substring(cardNumber.length() - 4);
}
}
- CreditCardPayment,PayPalPayment为新系统的支付实现类。
/**
* 旧系统支付适配器
*/
public class ThirdPartyPaymentAdapter implements UnifiedPayment {
private ThirdPartyPayment thirdPartyPayment;
private String account;
public ThirdPartyPaymentAdapter(ThirdPartyPayment thirdPartyPayment, String account) {
this.thirdPartyPayment = thirdPartyPayment;
this.account = account;
}
@Override
public void processPayment(double amount, String paymentDetails) {
System.out.println("Processing third party payment - " + paymentDetails);
thirdPartyPayment.makePayment(amount, account);
}
}
- ThirdPartyPaymentAdapter 为旧支付系统适配类,对新支付接口类 UnifiedPayment 进行了实现,并持有旧支付系统 ThirdPartyPayment 的引用。
PaymentProcessor
public class PaymentProcessor {
private UnifiedPayment paymentMethod;
private static Map<String, UnifiedPayment> paymentMethods = new HashMap<>();
public PaymentProcessor(UnifiedPayment paymentMethod) {
this.paymentMethod = paymentMethod;
}
public void executePayment(double amount, String details) {
paymentMethod.processPayment(amount, details);
}
// 注册支付方法
public static void registerPaymentMethod(String name, UnifiedPayment method) {
paymentMethods.put(name, method);
}
// 获取支付方法
public static UnifiedPayment getPaymentMethod(String name) {
return paymentMethods.get(name);
}
}
public class PaymentProcessorUtil {
public static void processOrderPayment(double amount, String method, String details) {
System.out.println("\n=== Processing order payment ===");
UnifiedPayment paymentMethod = PaymentProcessor.getPaymentMethod(method);
if (paymentMethod != null) {
new PaymentProcessor(paymentMethod).executePayment(amount, details);
}
else {
System.out.println("Error: Payment method '" + method + "' not found!");
}
}
}
- PaymentProcessor 为支付策略处理器,通过支付方法的不同,引用不同的支付模块执行逻辑。PaymentProcessorUtil 为其工具类。
测试类
@Test
public void test_pay() {
// 注册支付方式
PaymentProcessor.registerPaymentMethod("credit", new CreditCardPayment("1234567812345678", "John Doe"));
PaymentProcessor.registerPaymentMethod("paypal", new PayPalPayment("john.doe@example.com"));
PaymentProcessor.registerPaymentMethod("alipay", new ThirdPartyPaymentAdapter(new AliPayService(), "alipay_123"));
PaymentProcessor.registerPaymentMethod("wechat", new ThirdPartyPaymentAdapter(new WeChatPayService(), "wechat_456"));
PaymentProcessorUtil.processOrderPayment(150.75, "credit", "Order #1001 - Laptop");
PaymentProcessorUtil.processOrderPayment(89.99, "paypal", "Order #1002 - Mouse");
PaymentProcessorUtil.processOrderPayment(299.00, "alipay", "Order #1003 - Monitor");
PaymentProcessorUtil.processOrderPayment(54.99, "wechat", "Order #1004 - Keyboard");
}
执行结果
=== Processing order payment ===
Processing credit card payment: $150.75
Card: ****_****_****_5678, Holder: John Doe
Payment details: Order #1001 - Laptop
=== Processing order payment ===
Processing PayPal payment: $89.99
PayPal account: john.doe@example.com
Payment details: Order #1002 - Mouse
=== Processing order payment ===
Processing third party payment - Order #1003 - Monitor
AliPay payment processed: $299.00 to account alipay_123
=== Processing order payment ===
Processing third party payment - Order #1004 - Keyboard
WeChatPay payment processed: $54.99 to account wechat_456
Process finished with exit code 0
适配器模式+装饰器模式
下面将展示一个结合适配器模式和装饰器模式的通用数据读取系统案例。适配器用于整合不同数据源,装饰器用于动态添加功能增强。
DataReader
/**
* 统一数据读取接口
*/
public interface DataReader {
String read() throws IOException;
String getSourceInfo();
}
- DataReader 读取数据的统一接口,为适配目标接口
DatabaseAccessor
/**
* 数据库读取类
*/
public class DatabaseAccessor {
public String fetchDataFromDB(String query) {
return "Database result for query: " + query;
}
}
- DatabaseAccessor 为被适配类,用于在数据库中读取数据。
DatabaseReaderAdapter
/**
* 数据库读取适配器
*/
public class DatabaseReaderAdapter implements DataReader {
private final DatabaseAccessor databaseAccessor;
private final String query;
public DatabaseReaderAdapter(DatabaseAccessor databaseAccessor, String query) {
this.databaseAccessor = databaseAccessor;
this.query = query;
}
@Override
public String read() throws IOException {
return databaseAccessor.fetchDataFromDB(query);
}
@Override
public String getSourceInfo() {
return "Database query: " + query;
}
}
- DatabaseReaderAdapter 适配器类,持有 DatabaseAccessor 原数据读取接口的引用。
DataReaderDecorator
/**
* 基础装饰器类
*/
public abstract class DataReaderDecorator implements DataReader {
protected final DataReader wrappedReader;
public DataReaderDecorator(DataReader wrappedReader) {
this.wrappedReader = wrappedReader;
}
@Override
public String read() throws IOException {
return wrappedReader.read();
}
@Override
public String getSourceInfo() {
return wrappedReader.getSourceInfo();
}
}
- DataReaderDecorator 基础装饰类,持有 DataReader 接口的引用,并在方法实现中调用 装饰类的 接口方法。
装饰器实现类
/**
* 压缩装饰器
*/
public class CompressionDecorator extends DataReaderDecorator {
public CompressionDecorator(DataReader wrappedReader) {
super(wrappedReader);
}
@Override
public String read() throws IOException {
String originalData = wrappedReader.read();
return this.compress(originalData);
}
private String compress(String data) {
return "Compressed(" + data.length() + " chars): " + data.substring(0, Math.min(20, data.length())) + "...";
}
@Override
public String getSourceInfo() {
return "[Compressed] " + wrappedReader.getSourceInfo();
}
}
/**
* 缓存装饰器
*/
public class CachingDecorator extends DataReaderDecorator {
private String cache;
public CachingDecorator(DataReader wrappedReader) {
super(wrappedReader);
}
@Override
public String read() throws IOException {
if (cache == null) {
System.out.println("Cache miss - reading from source");
cache = wrappedReader.read();
}
else {
System.out.println("Cache hit - returning cached data");
}
return cache;
}
@Override
public String getSourceInfo() {
return "[Cached] " + wrappedReader.getSourceInfo();
}
}
- CompressionDecorator,CachingDecorator为装饰器实现类,用于增强原有数据读取类,增加额外功能。
测试类
@Test
public void test_read() throws IOException {
DataReader dbReader = new DatabaseReaderAdapter(new DatabaseAccessor(), "SELECT * FROM users");
System.out.println("\n=== Basic Adapter Usage ===");
System.out.println(dbReader.getSourceInfo() + ": " + dbReader.read());
System.out.println("\n=== Adapter + Decorator Combination ===");
DataReader cachedDbReader = new CachingDecorator(dbReader);
System.out.println("First read: " + cachedDbReader.read());
System.out.println("Second read: " + cachedDbReader.read());
DataReader superReader = new CompressionDecorator(new CachingDecorator(new EncryptionDecorator(new FileReaderAdapter(new LegacyFileReader(), "D:\\sample.txt"))));
System.out.println("\n=== Super Reader ===");
System.out.println(superReader.getSourceInfo());
System.out.println("Data: " + superReader.read());
}
运行结果
=== Basic Adapter Usage ===
Database query: SELECT * FROM users: Database result for query: SELECT * FROM users
=== Adapter + Decorator Combination ===
Cache miss - reading from source
First read: Database result for query: SELECT * FROM users
Cache hit - returning cached data
Second read: Database result for query: SELECT * FROM users
=== Super Reader ===
[Compressed] [Cached] [Encrypted] File: D:\sample.txt
Cache miss - reading from source
Data: Compressed(16 chars): MTIzMzIxMTIzMzIx...
Process finished with exit code 0
适配器模式+外观模式
下面将式和外观模式的跨平台文件管理系统案例。这个案例具有普遍性,适用于需要整合不同系统API并提供简化接口的场景。
FileSystem
/**
* 统一文件操作接口
*/
public interface FileSystem {
void createFile(String path);
void deleteFile(String path);
String readFile(String path);
void writeFile(String path, String content);
String getFileInfo(String path);
}
- FileSystem 适配目标类
被适配类
/**
* Windows 文件系统
* <p>
* 被适配对象
*/
public class WindowsNativeFileSystem {
public void createNewFile(String path) {
System.out.println("Windows: Creating file at " + path);
}
public void removeFile(String path) {
System.out.println("Windows: Deleting file at " + path);
}
public String readFileContent(String path) {
return "Windows file content from " + path;
}
public void writeToFile(String path, String content) {
System.out.println("Windows: Writing to file at " + path + ", content: " + content);
}
public String getFileMetadata(String path) {
return "Windows file info: " + path + ", size: 1024 bytes";
}
}
/**
* Linux 文件操作
* <p>
* 被适配对象类
*/
public class LinuxNativeFileOperations {
public void touchFile(String path) {
System.out.println("Linux: Creating file at " + path);
}
public void rmFile(String path) {
System.out.println("Linux: Removing file at " + path);
}
public String catFile(String path) {
return "Linux file content from " + path;
}
public void echoToFile(String path, String content) {
System.out.println("Linux: Writing to file at " + path + ", content: " + content);
}
public String lsFile(String path) {
return "Linux file info: " + path + ", permissions: rw-r--r--";
}
}
- 被适配类,提供了 Linux,Windows 文件相关操作方法。
适配器类
/**
* Linux 文件系统适配器
*/
public class LinuxFileSystemAdapter implements FileSystem {
private final LinuxNativeFileOperations linuxFileSystem;
public LinuxFileSystemAdapter(LinuxNativeFileOperations linuxFileSystem) {
this.linuxFileSystem = linuxFileSystem;
}
@Override
public void createFile(String path) {
linuxFileSystem.touchFile(path);
}
@Override
public void deleteFile(String path) {
linuxFileSystem.rmFile(path);
}
@Override
public String readFile(String path) {
return linuxFileSystem.catFile(path);
}
@Override
public void writeFile(String path, String content) {
linuxFileSystem.echoToFile(path, content);
}
@Override
public String getFileInfo(String path) {
return linuxFileSystem.lsFile(path);
}
}
/**
* windows 文件系统 适配器
*/
public class WindowsFileSystemAdapter implements FileSystem {
private final WindowsNativeFileSystem windowsFileSystem;
public WindowsFileSystemAdapter(WindowsNativeFileSystem windowsFileSystem) {
this.windowsFileSystem = windowsFileSystem;
}
@Override
public void createFile(String path) {
windowsFileSystem.removeFile(path);
}
@Override
public void deleteFile(String path) {
windowsFileSystem.removeFile(path);
}
@Override
public String readFile(String path) {
return windowsFileSystem.readFileContent(path);
}
@Override
public void writeFile(String path, String content) {
windowsFileSystem.writeToFile(path, content);
}
@Override
public String getFileInfo(String path) {
return windowsFileSystem.getFileMetadata(path);
}
}
FileManagerFacade
/**
* 外观类
*/
public class FileManagerFacade {
/**
* 文件系统引用(适配器引用)
*/
private FileSystem currentFileSystem;
private List<String> operationLog = new ArrayList<>();
public FileManagerFacade(String osType) {
switch (osType.toLowerCase()) {
case "windows":
currentFileSystem = new WindowsFileSystemAdapter(new WindowsNativeFileSystem());
break;
case "linux":
currentFileSystem = new LinuxFileSystemAdapter(new LinuxNativeFileOperations());
break;
default:
throw new IllegalArgumentException("Unsupported OS type: " + osType);
}
}
public void switchFileSystem(String osType) {
switch (osType.toLowerCase()) {
case "windows":
currentFileSystem = new WindowsFileSystemAdapter(new WindowsNativeFileSystem());
break;
case "linux":
currentFileSystem = new LinuxFileSystemAdapter(new LinuxNativeFileOperations());
break;
default:
throw new IllegalArgumentException("Unsupported OS type: " + osType);
}
this.logOperation("Switched to " + osType + " file system");
}
/**
* 创建并写入文件
*
* @param path
* @param content
*/
public void createAndWriteFile(String path, String content) {
currentFileSystem.createFile(path);
currentFileSystem.writeFile(path, content);
this.logOperation("Created and wrote to file: " + path);
}
/**
* 读取并删除文件
*
* @param path
* @return
*/
public String readAndDeleteFile(String path) {
String content = currentFileSystem.readFile(path);
currentFileSystem.deleteFile(path);
this.logOperation("Read and deleted file: " + path);
return content;
}
/**
* 获取文件信息摘要
*
* @param path 文件地址
* @return
*/
public String getFileSummary(String path) {
String info = currentFileSystem.getFileInfo(path);
this.logOperation("Retrieved file info: " + path);
return "File Summary: \n" + info + "\nContent Preview: " + currentFileSystem.readFile(path).substring(0, Math.min(20, info.length()));
}
public List<String> getOperationLog() {
return new ArrayList<>(operationLog);
}
private void logOperation(String message) {
operationLog.add(message);
}
}
- FileManagerFacade 外观类,持有 FileSystem 接口的引用,并在原有接口基础上,整合繁杂接口,提供统一的高层次接口。
测试类
@Test
public void test_file() {
FileManagerFacade fileManager = new FileManagerFacade("windows");
System.out.println("=== Window 文件操作 ===");
fileManager.createAndWriteFile("D:\\test\\demo.txt", "Hello Windows");
System.out.println(fileManager.getFileSummary("D:\\test\\demo.txt"));
fileManager.switchFileSystem("linux");
System.out.println("\n=== Linux 文件操作 ===");
fileManager.createAndWriteFile("/home/user/test.txt", "Hello Linux");
System.out.println(fileManager.readAndDeleteFile("/home/user/test.txt"));
System.out.println("\n=== 操作日志 ===");
fileManager.getOperationLog().forEach(System.out::println);
}
运行结果
=== Window 文件操作 ===
Windows: Deleting file at D:\test\demo.txt
Windows: Writing to file at D:\test\demo.txt, content: Hello Windows
File Summary:
Windows file info: D:\test\demo.txt, size: 1024 bytes
Content Preview: Windows file content
=== Linux 文件操作 ===
Linux: Creating file at /home/user/test.txt
Linux: Writing to file at /home/user/test.txt, content: Hello Linux
Linux: Removing file at /home/user/test.txt
Linux file content from /home/user/test.txt
=== 操作日志 ===
Created and wrote to file: D:\test\demo.txt
Retrieved file info: D:\test\demo.txt
Switched to linux file system
Created and wrote to file: /home/user/test.txt
Read and deleted file: /home/user/test.txt
Process finished with exit code 0
优势
- 接口统一与简化
- 适配器模式:统一不同操作系统的文件操作接口
- 外观模式:提供更高级的简化操作
- 降低系统复杂度
- 适配器隐藏了不同平台的实现细节
- 外观提供了更简单的接口,屏蔽了复杂操作序列
长话短说
组合后的优势
解耦
适配器模式本身就致力于解耦不兼容的接口,当它与工厂模式、策略模式等组合时,进一步将对象的创建、 行为选择等负责逻辑从核心业务逻辑中分离出来。
开闭原则的遵循
组合模式使得系统能够更好的遵循 "开闭原则",当有新的需求时,通常只需要添加新的类,而无需修改已有 的稳定代码,大大降低了系统维护的成本和引入新错误的风险。
动态行为
装饰器模式的引入,使得我们可以在运行时动态的为对象添加或移除功能,而无需修改其原始类,这种灵活性 在需要根据不同场景或用户偏好提供不同功能组合时尤为重要。
适配器模式负责接口转换, 工厂模式负责对象创建, 策略模式负责行为封装, 装饰器模式负责功能增强, 外观模式负责简化复杂子系统。
目前还没探索出相对合理的学习路线,只能通过不断联系,熟悉各种设计模式,并进行代码练习,以达到熟能生巧的作用。
相关推荐
- 如何设计一个优秀的电子商务产品详情页
-
加入人人都是产品经理【起点学院】产品经理实战训练营,BAT产品总监手把手带你学产品电子商务网站的产品详情页面无疑是设计师和开发人员关注的最重要的网页之一。产品详情页面是客户作出“加入购物车”决定的页面...
- 怎么在JS中使用Ajax进行异步请求?
-
大家好,今天我来分享一项JavaScript的实战技巧,即如何在JS中使用Ajax进行异步请求,让你的网页速度瞬间提升。Ajax是一种在不刷新整个网页的情况下与服务器进行数据交互的技术,可以实现异步加...
- 中小企业如何组建,管理团队_中小企业应当如何开展组织结构设计变革
-
前言写了太多关于产品的东西觉得应该换换口味.从码农到架构师,从前端到平面再到UI、UE,最后走向了产品这条不归路,其实以前一直再给你们讲.产品经理跟项目经理区别没有特别大,两个岗位之间有很...
- 前端监控 SDK 开发分享_前端监控系统 开源
-
一、前言随着前端的发展和被重视,慢慢的行业内对于前端监控系统的重视程度也在增加。这里不对为什么需要监控再做解释。那我们先直接说说需求。对于中小型公司来说,可以直接使用三方的监控,比如自己搭建一套免费的...
- Ajax 会被 fetch 取代吗?Axios 怎么办?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!今天给大家带来的主题是ajax、fetch...
- 前端面试题《AJAX》_前端面试ajax考点汇总
-
1.什么是ajax?ajax作用是什么?AJAX=异步JavaScript和XML。AJAX是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX可以使网页实...
- Ajax 详细介绍_ajax
-
1、ajax是什么?asynchronousjavascriptandxml:异步的javascript和xml。ajax是用来改善用户体验的一种技术,其本质是利用浏览器内置的一个特殊的...
- 6款可替代dreamweaver的工具_替代powerdesigner的工具
-
dreamweaver对一个web前端工作者来说,再熟悉不过了,像我07年接触web前端开发就是用的dreamweaver,一直用到现在,身边的朋友有跟我推荐过各种更好用的可替代dreamweaver...
- 我敢保证,全网没有再比这更详细的Java知识点总结了,送你啊
-
接下来你看到的将是全网最详细的Java知识点总结,全文分为三大部分:Java基础、Java框架、Java+云数据小编将为大家仔细讲解每大部分里面的详细知识点,别眨眼,从小白到大佬、零基础到精通,你绝...
- 福斯《死侍》发布新剧照 "小贱贱"韦德被改造前造型曝光
-
时光网讯福斯出品的科幻片《死侍》今天发布新剧照,其中一张是较为罕见的死侍在被改造之前的剧照,其余两张剧照都是死侍在执行任务中的状态。据外媒推测,片方此时发布剧照,预计是为了给不久之后影片发布首款正式预...
- 2021年超详细的java学习路线总结—纯干货分享
-
本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础重点知识点:数据类型、核心语法、面向对象...
- 不用海淘,真黑五来到你身边:亚马逊15件热卖爆款推荐!
-
Fujifilm富士instaxMini8小黄人拍立得相机(黄色/蓝色)扫二维码进入购物页面黑五是入手一个轻巧可爱的拍立得相机的好时机,此款是mini8的小黄人特别版,除了颜色涂装成小黄人...
- 2025 年 Python 爬虫四大前沿技术:从异步到 AI
-
作为互联网大厂的后端Python爬虫开发,你是否也曾遇到过这些痛点:面对海量目标URL,单线程爬虫爬取一周还没完成任务;动态渲染的SPA页面,requests库返回的全是空白代码;好不容易...
- 最贱超级英雄《死侍》来了!_死侍超燃
-
死侍Deadpool(2016)导演:蒂姆·米勒编剧:略特·里斯/保罗·沃尼克主演:瑞恩·雷诺兹/莫蕾娜·巴卡林/吉娜·卡拉诺/艾德·斯克林/T·J·米勒类型:动作/...
- 停止javascript的ajax请求,取消axios请求,取消reactfetch请求
-
一、Ajax原生里可以通过XMLHttpRequest对象上的abort方法来中断ajax。注意abort方法不能阻止向服务器发送请求,只能停止当前ajax请求。停止javascript的ajax请求...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)
- JS Loop For (32)
