首页 > 其他分享 >适配器模式

适配器模式

时间:2024-02-28 10:34:34浏览次数:34  
标签:插头 适配器 接口 public 插座 模式 void

简介

适配器模式是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一个接口。适配器模式通常用于解决两个不兼容接口之间的兼容性问题,使得原本由于接口不匹配而无法一起工作的类能够协同工作。

适配器模式主要由三个角色组成:

  1. 目标接口(Target Interface):客户端所期望使用的接口。适配器模式的目标是使得原本不兼容的接口能够通过目标接口进行访问。

  2. 源接口(Adaptee):需要被适配的接口。这是原始的接口,其功能可能与目标接口不匹配。

  3. 适配器(Adapter):这是一个具体的类,它实现了目标接口,并且包装了一个或多个源接口的实例。适配器接收来自客户端的请求,并将这些请求转发给源接口的实例,以便与源接口协同工作。

适配器模式的实现可以通过对象适配器或类适配器来完成:

  • 对象适配器:适配器类将源接口的实例作为一个成员变量,然后实现目标接口。通过这种方式,适配器可以调用源接口的方法来实现目标接口的方法。

  • 类适配器:适配器类同时继承了目标接口和源接口。通过继承源接口,适配器可以直接调用源接口的方法,并通过实现目标接口来向客户端暴露适配后的接口。

案例

对象适配器

对象适配器模式在现实生活中的一个例子是使用不同种类的插头适配器来连接不同国家的电器。

想象一下你旅行到了一个国家,但是你带的电器插头与当地的插座不兼容。这时你需要一个插头适配器来解决这个问题。这个适配器就是对象适配器的一个例子。

具体来说,让我们以欧洲和美国的电器插头为例:

  • 在欧洲,常见的电器插头是双圆形的欧洲标准插头。
  • 在美国,常见的电器插头是两个扁平的插脚的美国标准插头。

如果你带了一个欧洲的电器到美国,你会发现插头无法直接插入美国的插座。这时,你可以使用一个插头适配器。这个适配器有一个欧洲标准插座的接口,以及一个美国标准插座的接口。当你插入这个适配器时,它会将欧洲标准插头的电器接口转换为美国标准插座的接口,这样你的电器就可以在美国正常使用了。

在这个例子中:

  • 目标接口是美国标准插座。
  • 源接口是欧洲标准插座。
  • 适配器是插头适配器,它包装了一个欧洲标准插座的实例,并实现了美国标准插座的接口。

通过这个适配器,你的电器就能够在美国的插座上正常运行,实现了不同标准之间的兼容性。

using System;

// 欧洲标准插座接口
interface IEuropeanSocket
{
    void ProvideElectricity();
}

// 欧洲标准插座实现
class EuropeanSocket : IEuropeanSocket
{
    public void ProvideElectricity()
    {
        Console.WriteLine("欧洲标准插座供电,使用双圆形插头。");
    }
}

// 美国标准插座接口
interface IUSASocket
{
    void SupplyElectricity();
}

// 美国标准插座实现
class USASocket : IUSASocket
{
    public void SupplyElectricity()
    {
        Console.WriteLine("美国标准插座供电,使用两个扁平插脚。");
    }
}

// 适配器类
class SocketAdapter : IUSASocket
{
    private IEuropeanSocket _europeanSocket;

    public SocketAdapter(IEuropeanSocket europeanSocket)
    {
        _europeanSocket = europeanSocket;
    }

    public void SupplyElectricity()
    {
        // 插头转换过程
        ConvertPlug();

        // 提供电源
        Console.WriteLine("2. 提供电源。");

        // 通知开始供电
        Console.WriteLine("3. 开始供电。");

        // 调用欧洲标准插座的方法
        _europeanSocket.ProvideElectricity();
    }

    private void ConvertPlug()
    {
        Console.WriteLine("1. 插头转换:将双圆形插头转换为两个扁平插脚。");
    }
}

// 客户端代码
class Program
{
    static void Main(string[] args)
    {
        // 创建一个欧洲标准插座
        IEuropeanSocket europeanSocket = new EuropeanSocket();

        // 创建一个适配器,将欧洲标准插座适配成美国标准插座
        SocketAdapter adapter = new SocketAdapter(europeanSocket);

        // 在美国使用适配后的插座
        Console.WriteLine("在美国使用适配后的插座:");
        adapter.SupplyElectricity();

        Console.ReadLine();
    }
}

类适配器

类适配器是通过多重继承实现的,这在许多编程语言中是不被支持的。在C#中,类适配器通常不太容易实现,因为C#不支持多重继承。不过,我们可以通过接口实现类似的功能。

以下是一个类似于类适配器的生活场景的例子:

假设你有一个游戏控制器类 GameController,它有一个方法 Move() 用于移动角色。现在你想要为这个控制器类添加一个新的方法 Jump(),但是由于某些原因,你无法直接修改 GameController 类。你可以使用适配器模式来解决这个问题。

首先,我们有 GameController 类和 Jump() 方法:

// 游戏控制器类
class GameController
{
    public void Move()
    {
        Console.WriteLine("移动角色");
    }
}

然后,我们创建一个接口 IJumpable,其中包含了 Jump() 方法:

// 跳跃接口
interface IJumpable
{
    void Jump();
}

接下来,我们创建一个适配器类 JumpAdapter,它继承了 GameController 类并实现了 IJumpable 接口,以添加跳跃功能:

// 适配器类(类适配器)
class JumpAdapter : GameController, IJumpable
{
    public void Jump()
    {
        Console.WriteLine("角色跳跃");
    }
}

现在,我们可以在客户端代码中使用适配器来移动和跳跃:

class Program
{
    static void Main(string[] args)
    {
        // 使用适配器实现移动和跳跃
        Jumpable jumpController = new JumpAdapter();
        jumpController.Move();
        jumpController.Jump();

        Console.ReadLine();
    }
}

完整代码

using System;

// 游戏控制器类
class GameController
{
    public void Move()
    {
        Console.WriteLine("移动角色");
    }
}

// 跳跃接口
interface IJumpable
{
    void Jump();
}

// 适配器类(类适配器)
class JumpAdapter : GameController, IJumpable
{
    public void Jump()
    {
        Console.WriteLine("角色跳跃");
    }
}

class Program
{
    static void Main(string[] args)
    {
        // 使用适配器实现移动和跳跃
        IJumpable jumpController = new JumpAdapter();
        jumpController.Move();
        jumpController.Jump();

        Console.ReadLine();
    }
}

项目实际案例

在 GUI 开发中,开始时使用 WinForms 来开发用户界面,并且使用了 FlowLayoutPanel 来管理布局。但是后来决定将用户界面迁移到 WPF,并使用 StackPanel 来管理布局。为了实现平滑的迁移,可以使用适配器模式。

以下是一个简化的示例:

首先是 WinForms 中使用的 FlowLayoutPanel:

using System.Windows.Forms;

public class WinFormsFlowLayout
{
    private readonly FlowLayoutPanel _flowLayoutPanel;

    public WinFormsFlowLayout()
    {
        _flowLayoutPanel = new FlowLayoutPanel();
    }

    public void AddControl(Control control)
    {
        _flowLayoutPanel.Controls.Add(control);
    }

    // 其他方法...
}

现在我们决定迁移到 WPF 并使用 StackPanel,我们可以创建一个适配器来适配 StackPanel:

using System.Windows.Controls;

public class WpfStackPanelAdapter : WinFormsFlowLayout
{
    private readonly StackPanel _stackPanel;

    public WpfStackPanelAdapter()
    {
        _stackPanel = new StackPanel();
    }

    public override void AddControl(Control control)
    {
        _stackPanel.Children.Add(new WindowsFormsHost { Child = control });
    }

    // 其他方法...
}

在这个例子中,WpfStackPanelAdapter 类继承自 WinFormsFlowLayout 类,但是重写了 AddControl() 方法。在重写的方法中,我们使用了 WindowsFormsHost 来将 WinForms 控件嵌入到 WPF 中的 StackPanel 中,以实现对 StackPanel 的适配。

通过这种方式,我们可以实现平滑的从 WinForms 到 WPF 的迁移,并且保留了原有的布局管理器接口,从而减少了对现有代码的修改。

优点:

  1. 增强灵活性:适配器模式允许客户端使用不兼容的接口,从而增强了系统的灵活性。它可以将现有的类与其他类协作,而无需修改其源代码。

  2. 重用现有功能:适配器模式可以重用现有类的功能,而无需修改其现有代码。这使得系统更容易维护和扩展。

  3. 解耦合:适配器模式将客户端与具体类解耦,客户端只需要与适配器交互,而不需要了解被适配的类的细节。

  4. 统一接口:适配器模式可以将多个类的接口统一成一个接口,使得客户端可以统一调用不同类的方法。

缺点:

  1. 增加复杂性:适配器模式引入了一个额外的适配器类,可能会增加系统的复杂性。

  2. 潜在性能损耗:适配器模式可能会引入一些性能损耗,因为适配器需要转换接口并委托给被适配的对象。

  3. 过多使用可能会导致设计问题:如果过度使用适配器模式,可能会导致系统中出现大量的适配器类,使得系统变得复杂和难以理解。因此,适配器模式应谨慎使用,只在需要时才使用。

 适用场景:

适配器模式通常在以下情况下使用:

  1. 使用现有类:当系统需要使用已经存在的类,但是其接口与系统要求的接口不匹配时,可以使用适配器模式。这样可以避免修改现有类的代码,同时也能够满足系统的需求。

  2. 集成第三方库:当需要集成第三方库或外部系统,并且它们的接口与系统接口不兼容时,可以使用适配器模式来进行集成,使得系统能够与第三方库无缝交互。

  3. 统一接口:当系统中存在多个类具有类似但不同的接口时,可以使用适配器模式将它们统一成一个接口,使得客户端可以统一调用不同类的方法。

  4. 复用已有功能:当需要复用现有类的功能,但是现有类的接口与系统要求的接口不匹配时,可以使用适配器模式来封装现有类,并将其接口适配成系统所需的接口。

  5. 透明地封装类:当需要将某个类的实现细节对客户端透明地隐藏时,可以使用适配器模式来封装该类,从而达到解耦合的目的。

总之,适配器模式适用于需要解决接口不兼容问题、统一接口、复用现有功能、透明封装类等场景。

标签:插头,适配器,接口,public,插座,模式,void
From: https://www.cnblogs.com/mchao/p/18039207

相关文章

  • 原型模式
    定义:原型模式(PrototypeDesignPattern)用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象原型模式主要解决的问题: 如果创建对象的成本较大,比如对象中的数据是经过复杂计算才能得到的,或者需要从RPC接口或者数据库等比较慢的IO中获取,这种情况我们......
  • 原型模式
    简介原型模式(PrototypePattern)是一种创建型设计模式,它允许创建新对象的同时,通过复制现有对象的方式来初始化新对象。这意味着在原型模式中,新对象的创建过程不再依赖于直接实例化类,而是通过复制已有对象的方式来进行。在原型模式中,存在一个原型对象(Prototype),它是需要被复制的对......
  • 建造者模式
    简介建造者模式(BuilderPattern)是一种创建型设计模式,用于构建复杂对象。它的主要目的是将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示形式。这种模式通常适用于创建对象的参数较多,且某些参数之间存在复杂的依赖关系的情况。在建造者模式中,通常会有一个建造......
  • C++特殊类的设计与单例模式
    //1.设计一个不能被拷贝的类/*解析:拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。C++98;将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即......
  • 详解在 centos 中引导到救援模式
    详解在centos中引导到救援模式Linux系统CentOS进入单用户模式和救援模式详解一、概述目前在运维日常工作中,经常会遇到服务器异常断电、忘记root密码、系统引导文件损坏无法进入系统等等操作系统层面的问题,给运维带来诸多不便,现将上述现象的解决方法和大家分享一下,本次主要以C......
  • Ubuntu如何进救援模式
    linux的救援模式-1详解在Ubuntu中引导到救援模式或紧急模式这篇教程将介绍如何在Ubuntu22.04、20.04和18.04LTS版本中引导到救援Rescue模式或紧急Emergency模式。你可能已经知道,在RHEL7、RHEL8、Ubuntu16.04LTS及其更新的版本的Linux发行版中运行等级R......
  • 设备管理器-网络适配器-Remote NDiS-based Internet Sharing Device(基于远程NDIS的互
    RemoteNDiS-basedInternetSharingDevice(基于远程NDIS的互联网共享设备)是一种网络接口遥控分享装置。这种设备允许通过USB连接将智能手机等设备连接到电脑,从而充当无线网卡的作用,使电脑能够连接到互联网。具体功能作用如下:充当无线网卡:当手机连接到互联网后,通过USB绑定,这个......
  • 设计模式--观察者(Observer)模式
    目录概念概念观察者模式(ObserverPattern)是C++中常用的一种设计模式,它定义了对象间的一种一对多的依赖关系。在这种模式中,当一个对象(被观察者,Subject)的状态发生改变时,所有依赖于它的对象(观察者,Observer)都会收到通知并自动更新。这种模式的结构通常包括四个部分:抽象主题(Subject......
  • 接口隔离原则(设计模式)
    定义“Clientsshouldnotbeforcedtodependuponinterfacesthattheydonotuse”个人认为接口隔离原则,和单一原则有点像。一个接口实现一个功能。 不过,你应该已经发现,接口隔离原则跟单一职责原则有点类似,不过稍微还是有点区别。单一职责原则针对的是模块、类、接口......
  • 里斯替换原则 (设计模式)
    定义IfSisasubtypeofT,thenobjectsoftypeTmaybereplacedwithobjectsoftypeS,withoutbreakingtheprogram。Functionsthatusepointersofreferencestobaseclassesmustbeabletouseobjectsofderivedclasseswithoutknowingit。子类能够替......