🚀介绍
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能 一起工作。
适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现 有组件库中的相关组件的内部结构,所以应用相对较少些。
适配器模式(Adapter)包含以下主要角色:
- 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
- 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
- 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者
适配器模式的分类
- 类适配器(Class Adapter):
- 在其他支持多重继承的语言中,类适配器通过多重继承来实现接口的匹配。但在C#中,由于不支持多重继承,这种方式无法直接使用。
- 然而,C#中的接口可以实现类似的功能,即一个类可以实现多个接口,并在其中实现接口的方法。但这并不等同于传统意义上的类适配器。
- 对象适配器(Object Adapter):
- 对象适配器是C#中更常用的适配器模式实现方式。
- 它通过组合一个类的实例(即适配者)来实现适配。适配器类持有一个适配者对象的引用,并通过该引用来调用适配者的方法。
- 在C#中,对象适配器通常是通过实现目标接口,并在其中调用适配者的方法来实现的。这样,客户端就可以通过目标接口来调用适配者的方法,而无需直接知道适配者的存在。
🚀案例
适配者Adaptee(已经存在,与接口不兼容的类),他有一个SpecificRequest(特殊请求)方法
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Called SpecificRequest()");
}
}
我们的目标接口Taget(切口中定义了一个请求方法)
interface ITarget
{
void Request();
}
适配器Adapter,在Adapter中,实现了我们的接口,但是实际上是调用了Adaptee的SpecificRequest方法
class Adapter : ITarget
{
// 适配器持有一个Adaptee对象的引用
private readonly Adaptee _adaptee;
// 构造函数,它接受一个Adaptee对象作为参数
public Adapter(Adaptee adaptee)
{
_adaptee = adaptee;
}
// 实现ITarget接口中的Request方法
// 在这个方法中,适配器调用了Adaptee的SpecificRequest方法
public void Request()
{
_adaptee.SpecificRequest();
}
}
然后!我们就可以通过 Adapter
对象(它现在被赋值给了 ITarget
接口类型的变量 target
)调用了 Request
方法。由于 Adapter
类实现了 ITarget
接口,并且 Request
方法在 Adapter
类中被实现为调用 Adaptee
对象的 SpecificRequest
方法,因此调用 target.Request()
实际上会执行 Adaptee
对象的 SpecificRequest
方法。
public static void Main(string[] args)
{
// 创建一个Adaptee对象
Adaptee adaptee = new Adaptee();
// 创建一个Adapter对象,并将adaptee对象传递给它
ITarget target = new Adapter(adaptee);
// 通过Adapter对象调用Request方法
// 这会间接地调用Adaptee对象的SpecificRequest方法
target.Request();
}
🚀优缺点
优点:
- 提高了类的复用性:适配器模式可以让两个没有任何关系的类一起运行。
- 增加了类的透明性:用户通过适配器可以调用目标接口,适配器对用户来说是透明的,用户并不需要知道适配器的存在。
- 提高了类的扩展性:如果想要替换或者增加被适配的类,只需要修改适配器或者增加新的适配器即可,原有代码无需修改,符合“开闭原则”。
- 灵活性好:适配器模式提供了一种“即插即用”的方式来适应业务变化,可以很方便地改变数据和对象的表现形式。
缺点:
- 过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明可以直接调用的函数,却非要在使用一个适配器,这无疑增加了系统的复杂度。
- 适配器类可能需要重新实现一些在适配者中已经存在的功能,这可能导致代码冗余。但是,在大多数情况下,这种冗余是可以接受的,因为适配器的主要目的是解决接口不兼容的问题。
使用场景:
- 系统需要使用现有的类,而这些类的接口不符合系统的需要。
- 想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
- 需要一个统一的输出接口,而输入端的类型不可预知。