在软件开发中,基本上任何问题都可以通过增加一个中间层来解决。适配器模式其实就是一个中间层。综上,适配器模式起着转化/委托的作用,将一种接口转化为另一种符合需求的接口。1
根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器模式
和类适配器模式
两种。
在类适配器模式中,适配器与适配者之间是继承(或实现)关系。
在对象适配器模式中,适配器与适配者之间是关联关系;
在实际开发中,对象适配器模式的使用频率更高。
// 目标接口
public interface IMediaPlayer
{
void Play(string audioType, string fileName);
}
// 现有类
public class AdvancedMediaPlayer
{
public void PlayVlc(string fileName)
{
// 播放VLC文件的逻辑
}
public void PlayMp4(string fileName)
{
// 播放MP4文件的逻辑
}
}
// 类适配器
public class MediaAdapter : AdvancedMediaPlayer, IMediaPlayer
{
private string audioType;
public MediaAdapter(string audioType)
{
this.audioType = audioType;
}
public void Play(string audioType, string fileName)
{
if (audioType.Equals("vlc", StringComparison.OrdinalIgnoreCase))
{
PlayVlc(fileName);
}
else if (audioType.Equals("mp4", StringComparison.OrdinalIgnoreCase))
{
PlayMp4(fileName);
}
}
}
var vlcmediaPlayer = new MediaAdapter("vlc");
vlcmediaPlayer.Play("SampleVideo.vlc");
var mp4MediaPlayer = new MediaAdapter("mp4");
mp4MediaPlayer.Play("SampleVideo.mp4");
// 目标接口
public interface ITarget
{
void Request();
}
// 现有类
public class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Adaptee.SpecificRequest()");
}
}
// 对象适配器
public class Adapter : ITarget
{
private Adaptee adaptee;
public Adapter(Adaptee adaptee)
{
this.adaptee = adaptee;
}
public void Request()
{
adaptee.SpecificRequest();
}
}
var adaptee = new Adaptee();
var objectAdapter = new Adapter(adaptee);
objectAdapter.Request();
假设有一个智能窗帘和一个智能温控器,
智能窗帘可以通过调用OpenCurtain
和CloseCurtain
方法来控制开合,
智能温控器可以通过调用IncreaseTemperature
和DecreaseTemperature
方法来调节温度。
现希望智能窗帘能够根据温度自动开合,同时智能温控器也能根据窗帘的状态调整温度,以实现更智能的家居环境控制。
// 智能窗帘接口
public interface ISmartCurtain
{
void OpenCurtain();
void CloseCurtain();
}
// 智能温控器接口
public interface ISmartThermostat
{
void IncreaseTemperature();
void DecreaseTemperature();
}
// 智能窗帘实现类
public class SmartCurtain : ISmartCurtain
{
public void OpenCurtain()
{
Console.WriteLine("智能窗帘打开");
}
public void CloseCurtain()
{
Console.WriteLine("智能窗帘关闭");
}
}
// 智能温控器实现类
public class SmartThermostat : ISmartThermostat
{
public void IncreaseTemperature()
{
Console.WriteLine("智能温控器升温");
}
public void DecreaseTemperature()
{
Console.WriteLine("智能温控器降温");
}
}
public class SmartHomeAdapter : ISmartCurtain, ISmartThermostat
{
private ISmartCurtain smartCurtain;
private ISmartThermostat smartThermostat;
public ISmartCurtain SmartCurtain { set => smartCurtain = value; }
public ISmartThermostat SmartThermostat { set => smartThermostat = value; }
public void OpenCurtain()
{
Console.Write("根据温度自动 ");
smartCurtain.OpenCurtain();
smartThermostat.DecreaseTemperature(); // 窗帘打开时,适当降温
}
public void CloseCurtain()
{
Console.Write("根据温度自动 ");
smartCurtain.CloseCurtain();
smartThermostat.IncreaseTemperature(); // 窗帘关闭时,适当升温
}
public void IncreaseTemperature()
{
Console.Write("根据窗帘状态自动 ");
smartThermostat.IncreaseTemperature();
smartCurtain.CloseCurtain(); // 升温时,关闭窗帘以保持温度
}
public void DecreaseTemperature()
{
Console.Write("根据窗帘状态自动 ");
smartThermostat.DecreaseTemperature();
smartCurtain.OpenCurtain(); // 降温时,打开窗帘以促进空气流通
}
}
public class Program
{
public static void Main()
{
ISmartCurtain smartCurtain = new SmartCurtain();
ISmartThermostat smartThermostat = new SmartThermostat();
SmartHomeAdapter adapter = new SmartHomeAdapter();
adapter.SmartCurtain = smartCurtain;
adapter.SmartThermostat = smartThermostat;
// 根据温度自动控制窗帘和温控器
ISmartCurtain curtainAdapter = adapter;
curtainAdapter.OpenCurtain(); // 根据温度自动打开窗帘并适当降温
curtainAdapter.CloseCurtain(); // 根据温度自动关闭窗帘并适当升温
// 根据窗帘状态自动调整温度
ISmartThermostat thermostatAdapter = adapter;
thermostatAdapter.IncreaseTemperature(); // 根据窗帘状态自动升温并关闭窗帘
thermostatAdapter.DecreaseTemperature(); // 根据窗帘状态自动降温并打开窗帘
}
}
// 目标接口
public interface IDevice
{
void PowerOn();
void PowerOff();
void Reset();
void Upgrade();
}
// 缺省适配器
public abstract class DefaultDeviceAdapter : IDevice
{
public virtual void PowerOn()
{
// 默认空实现
}
public virtual void PowerOff()
{
// 默认空实现
}
public virtual void Reset()
{
// 默认空实现
}
public virtual void Upgrade()
{
// 默认空实现
}
}
// 具体适配器类
public class ConcreteDeviceAdapter : DefaultDeviceAdapter
{
public override void PowerOn()
{
Console.WriteLine("设备开机");
}
public override void PowerOff()
{
Console.WriteLine("设备关机");
}
}
IDevice device = new ConcreteDeviceAdapter();
device.PowerOn(); // 输出:设备开机
device.PowerOff(); // 输出:设备关机
适配器模式主要用于解决接口不兼容的问题,使得原本无法协同工作的类或系统能够顺利交互。以下是适配器模式适用的主要场景:
集成第三方库或组件:适配器模式用于解决系统与第三方库接口不兼容的问题,如支付网关接口转换。
复用旧代码:适配器模式允许在不修改旧代码的情况下,将其接口适配到新系统需求,如旧日志记录类适配新接口。
统一多个类的接口:适配器模式可将多个功能相似但接口不一致的类统一为一致接口,如多种数据库操作接口统一。
与外部系统交互:适配器模式用于与接口不兼容的外部系统交互,如物联网应用中不同硬件设备协议的转换。
测试驱动开发(TDD):适配器模式可模拟不兼容的依赖项行为,如测试中模拟外部服务的行为。
例如 OrderProcessor
,它依赖于一个外部服务 PaymentService
来处理支付。
PaymentService
是一个第三方服务,它的接口可能比较复杂,或者它的调用可能会产生副作用(如真实的支付操作)。
在测试 OrderProcessor
时,并不希望真正调用 PaymentService
,此时就可以使用适配器模式,写一个Mock测试实现IPaymentService
,模拟支持成功的行为,,以便专注于测试 OrderProcessor
的逻辑。
支持多种数据格式:适配器模式可将不同数据格式转换为统一接口,如从JSON、XML、数据库等数据源读取数据。
逐步重构系统:适配器模式用于新旧模块接口不一致时的协同工作,如单体应用拆分为微服务时的接口适配。
跨平台开发:适配器模式用于统一不同平台的API接口,如跨平台文件操作工具的开发。
硬件抽象:适配器模式用于统一多种硬件设备的接口,如支持多种品牌打印机的驱动系统。
接口升级:适配器模式用于在接口升级时保留旧接口的兼容性,如API升级时适配旧版本客户端。
DataAdapter
:DataAdapter
(如 SqlDataAdapter
、OleDbDataAdapter
)是一个典型的适配器模式应用。DataSet
接口。public void DataAdapterDemoMethod()
{
string connectionString = "connection_string";
string query = "SELECT * FROM Customers";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
DataSet dataSet = new DataSet();
// 填充 DataSet
adapter.Fill(dataSet, "Customers");
// 访问 DataSet 中的数据
foreach (DataRow row in dataSet.Tables["Customers"].Rows)
{
Console.WriteLine(row["CustomerName"]);
}
}
}
HttpClient
和HttpMessageHandler
:HttpClient
使用 HttpMessageHandler
来处理 HTTP 请求。HttpMessageHandler
,以适配不同的 HTTP 请求处理逻辑。using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class CustomHandler : DelegatingHandler
{
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// 在发送请求之前可以添加自定义逻辑
Console.WriteLine("Request sent to: " + request.RequestUri);
// 继续处理请求
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
// 在收到响应之后可以添加自定义逻辑
Console.WriteLine("Response received with status code: " + response.StatusCode);
return response;
}
}
class Program
{
static async Task Main()
{
HttpClient client = new HttpClient(new CustomHandler());
HttpResponseMessage response = await client.GetAsync("https://jsonplaceholder.typicode.com/posts/1");
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}
}
这一部分等更新了其他设计模式的内容,再进行更新。
适配器模式的核心思想是将一个接口转换为另一个接口,使得原本不兼容的接口能够协同工作。它的主要优点是:
适配器模式也不应滥用。如果接口本身设计合理,或者可以通过重构直接统一接口,那么就不需要使用适配器模式。
《设计模式就该这样学: 基于经典框架源码和真实业务场景》——谭勇德 ↩︎