二十三种设计模式[6]

前言

       适配器,属于类结构型模式。《设计模式 - 可复用的面向对象软件》一书中将之描述为“ 将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 ”。

       在日常生活中,我们经常遇到“不兼容”的情况。比如充电器的插头与插座不兼容,手机的接口与电脑的接口兼容等等。遇到这些问题,一般我们的解决办法是在两个不兼容的物件之间增加一个转换器,达到(间接)兼容的目的。而在软件开发的过程中,我们使两个接口兼容的方式就是适配器模式。

结构

       适配器模式分为类适配对象适配两种,具体结构如下:

类适配:

Adapter_1

对象适配:

Adapter_2

在适配器模式中,需要角色如下:

  • Target(目标抽象): 调用者直接使用的抽象;
  • Adapter(适配器): 目标抽象的子类或实现类,对Target和Adaptee进行适配;
  • Adaptee(被适配的类): 一般情况下是一个已存在的需要与之兼容的类;

示例

       考虑一个文本编辑器,它的首要任务是对各类文件进行解析,每种文件的解析方法由接口IFileParseService的各个实现类实现,并且已经在TxtParse类中实现了对.txt文件的解析。在对这个文本编辑器进行扩展来支持.xm和.sqll文件时引用了包含解析方法的第三方库FileParseTool。接下来看看如何使用类适配和对象适配使接口IFileParseService与FileParseTool兼容。

Adapter_3

  • 类适配(XmlFileParse)

public interface IFileParseTool
{
    string FileParsing();
}

public class XmlFileParseTool : IFileParseTool
{
    public string FileParsing()
    {
        return "Xml文件解析中...";
    }
}

public interface IFileParseService
{
    string Parsing();
}

public class XmlFileParse : XmlFileParseTool, IFileParseService
{
    public string Parsing()
    {
        return base.FileParsing();
    }
}

static void Main(string[] args)
{
    IFileParseService xmlParseService = new XmlFileParse();
    Console.WriteLine(xmlParseService.Parsing());
    Console.ReadKey();
}

       由于每个类只能继承一个类,所以当我们需要同时适配多个类时,类适配并不能满足我们的需求。

  • 对象适配(SqlFileParse)

public interface IFileParseTool
{
    string FileParsing();
}

public class SqlFileParseTool : IFileParseTool
{
    public string FileParsing()
    {
        return "Sql文件解析中...";
    }
}

public interface IFileParseService
{
    string Parsing();
}

public class SqlFileParse : IFileParseService
{
    public SqlFileParse(IFileParseTool parseTool)
    {
        this._parseTool = parseTool;
    }

    private IFileParseTool _parseTool = null;

    public string Parsing()
    {
        return this._parseTool.FileParsing();
    }
}

static void Main(string[] args)
{
    IFileParseTool sqlParseTool = new SqlFileParseTool();
    IFileParseService sqlParseService = new SqlFileParse(sqlParseTool);
    Console.WriteLine(sqlParseService.Parsing());
    Console.ReadKey();
}

       对象适配的方式使得适配器更加灵活,并且可同时适配多个类。另外,对象适配还可通过同一个适配器既可以使接口IFileParseService适配IFileParseTool的同时使IFileParseTool适配接口IFileParseService,达到双向适配的效果。如下:

  • 双向适配(FileParse)

Adapter_4

public interface IFileParseTool
{
    string FileParsing();
}

public class XmlFileParseTool : IFileParseTool
{
    public string FileParsing()
    {
        return "Xml文件解析中...";
    }
}

public interface IFileParseService
{
    string Parsing();
}

public class TxtFileParse : IFileParseService
{
    public string Parsing()
    {
        return "Txt文件解析中...";
    }
}

public class FileParse : IFileParseService, IFileParseTool
{
    private IFileParseService _parseService = null;
    private IFileParseTool _parseTool = null;

    public FileParse(IFileParseService parseService)
    {
        this._parseService = parseService;
    }

    public FileParse(IFileParseTool parseTool)
    {
        this._parseTool = parseTool;
    }

    /// <summary>
    /// 接口IFileParseTool的实现
    /// </summary>
    /// <returns></returns>
    public string FileParsing()
    {
        return this._parseService.Parsing();
    }

    /// <summary>
    /// 接口IFileParseService的实现
    /// </summary>
    /// <returns></returns>
    public string Parsing()
    {
        return this._parseTool.FileParsing();
    }
}

static void Main(string[] args)
{
    //接口IFileParseService兼容IFileParseTool
    IFileParseService parseService = new FileParse(new XmlFileParseTool());
    Console.WriteLine(parseService.Parsing());

    //接口IFileParseTool兼容IFileParseService
    IFileParseTool parseTool = new FileParse(new TxtFileParse());
    Console.WriteLine(parseTool.FileParsing());

    Console.ReadKey();
}
  • 接口适配器

       接口适配器,又称默认适配器。一般在一个类实现一个接口又不想或不需要实现接口中的所有方法时去创建一个实现这个接口的抽象类,并为该接口中的每个方法提供一个默认的实现(比如控方法),再由类去继承这个抽象类。这样就可以在类中由选择性的重写方法。

Adapter_5

总结

       适配器模式主要的目的是用来使不兼容的接口能够在一起工作,提高了类的复用,以及程序的灵活性。但过多的使用适配器会让程序的调用显得比较混乱。更多情况下,适配器模式在扩展现有程序下使用。

       以上,就是我对适配器模式的理解,希望对你有所帮助。

       示例源码:https://gitee.com/wxingChen/DesignPatternsPractice

       系列汇总:https://www.cnblogs.com/wxingchen/p/10031592.html

       本文著作权归本人所有,如需转载请标明本文链接(https://www.cnblogs.com/wxingchen/p/10078587.html)

原文地址:https://www.cnblogs.com/wxingchen/p/10078587.html