您的位置:知识库 » 软件设计

系统架构技能之设计模式—适配器模式

作者: CallHot  来源: 博客园  发布时间: 2010-12-21 16:21  阅读: 2555 次  推荐: 0   原文链接   [收藏]  

  一、上篇回顾

  通过上篇的简单讲解,我们知道了,组合模式意图是通过整体与局部之间的关系,通过树形结构的形式进行组织复杂对象,屏蔽对象内部的细节,对外展现统一的方式来操作对象,是我们处理更复杂对象的一个手段和方式。本文以查询控件为例,说明了,查询控件内部的组成元素,及如何操作内部的组成元素,包括添加元素,删除和处理相应事件的Handler,当然组合模式的作用远比这些强大,后面我们肯定会在一些实例代码中运用到组合模式的。组合模式如果在条件允许的情况下,我们尽量使用组合模式来处理复杂对象,远比通过继承出来的对象来的有效。

  组合模式-强调的是如何组织整体和局部之间的结构,将整体和局部之间的关系,通过树形这样的结构来组织这种对象组合的结构关系。

  组合模式的适用场景:

  1、我们期望操作一个复杂对象和操作一个组成这个复杂对象内部的简单对象一样操作的时候,我们可以考虑对象组合。

  2、当一个对象由多个简单对象组成,并且它又可能是其他对象的一个组成部分,这种情况下,组合模式是比较好的选择。

  二、摘要

  本篇将会讲述结构型模式中的经典模式-适配器模式,也是项目中经常使用的模式之一,我们现在开发一个系统的时候,也许会遇到各式各样的要求,我们要求和现有的系统进行集成,或者是我们直接开发一个系统,或者是我们修改已有的系统达到满足现有需求的要求。因此一般来说,每种情况,我们都有自己的应对方案。我们来看看项目中的几种可能情况:

image

  通过上面的几种情况,我们知道,开发一个新系统吧,成本和时间的投入较高,如果说我们旧系统目前运行的非常稳定,并且投入的成本非常高,我们既想继续使用旧系统的功能,又想满足新系统的需求,这个时候,我们怎么做呢?可能比较好的方式就是把旧系统通过适配器来转换成新接口的调用形式,完成适配服务。当然本文也是主要针对这个思路,展开去讲述适配器模式的一些用法,当然我这里可能讲解了适配器模式的一些普遍用法,还有一些比较特殊的用法,需要大家多多指出,向大伙学习了。

  本文主要讲述下面的几个部分的内容:

  1、适配器模式的使用场景。

  2、适配器模式的经典实现。

  3、多适配器的封装。

  4、其他情况的考虑。

  三、本文大纲

  a、上篇回顾。

  b、摘要。

  c、本文大纲。

  d、适配器模式的特点及使用场景。

  e、适配器模式的经典实现。

  f、适配器模式的其他方案。

  g、适配器模式使用总结。

  四、适配器模式的特点及使用场景

  4.1、适配器模式的特点

  适配器模式主要解决的问题就是我们要调用的接口类型,无法满足我们新系统的使用需求,这时候,我们需要将旧系统的接口,通过适配器进行转配,达到支持新接口调用的目的。对于这样的要求,我们通过适配器就可以完成,当然如果有多个接口需要转配,那么我们就需要为每一个接口提供一个适配器去完成转换的工作。当然具体的调用过程,我们可以进行相应的封装。达到比较通用的方式去调用适配器,完成适配服务。我们来看看适配的过程。        image  上图基本给出了适配器的基本转换的过程。

  4.2、适配器模式的场景

  我们根据上面的适配器的特点的介绍中,我们来分析下适配器模式的几类比较适用的使用场景:

  1、我们在使用第三方的类库,或者说第三方的API的时候,我们通过适配器转换来满足现有系统的使用需求。

  2、我们的旧系统与新系统进行集成的时候,我们发现旧系统的数据无法满足新系统的需求,那么这个时候,我们可能需要适配器,完成调用需求。

  3、我们在使用不同数据库之间进行数据同步。(我这里只是分析的是通过程序来说实现的时候的情况。还有其他的很多种方式[数据库同步])。

  五、适配器模式的经典实现

  我们本节给出适配器模式的经典实现代码,我们这里结合项目中的查询服务来进行说明,旧系统中提供一个查询服务方法Query();但是我新系统定义底层的数据访问服务层的时候,却是使用的GetList()方法,并且将之前的返回结果集合进行包装成泛型的形式来进行。我们这里给出相关的示例代码,大家就能清楚这个使用过程了,当然我们这里给出类适配器和对象适配器2种实现的方式,通过不同的实现思路,我们最后总结下,这2种形式的优缺点:

  1、类适配器

  针对上面描述的接口的转配过程,我们给出示例代码:

旧系统的查询服务:
public class Query :IQuery
{
public object Query()
{
return new object();
}
}
新系统的查询服务接口:
public interface ISelect
{
object GetList();
}
通过类适配器完成转配操作:
public class QueryAdapter : Query, ISelect
{
public object GetList()
{
return base.Query();
}
}
具体的调用测试代码如下:
class Program
{
static void Main(string[] args)
{
ISelect adapter
= new QueryAdapter();
object o= adapter.GetList();
System.Threading.Thread.Sleep(
10000);

}
}

  2、对象适配器

旧系统的查询服务:
public class Query :IQuery
{
public object Query()
{
return new object();
}
}
新系统的查询服务接口:
public interface ISelect
{
object GetList();
}
通过类适配器完成转配操作:
public class QueryAdapter : ISelect
{
private Query query = new Query();

public object GetList()
{
return query.Query();
}
}
具体的调用测试代码如下:
class Program
{
static void Main(string[] args)
{
ISelect adapter
= new QueryAdapter();
object o= adapter.GetList();
System.Threading.Thread.Sleep(
10000);
}
}

  上面我们就完成了经典的适配器模式的简单实现,当然上面也没有考虑通用性等各方面的内容,只是给出了一个大概的实现,当然对于上面的适配器的创建过程,我们可以通过前面讲述的创建型模式中的几个实现方案,进行相应的改进。

  六、适配器模式的其他方案

  上面给出了适配器模式的经典实现,参考其他篇讲述的方式,我们给出适配器模式的其他演变方式

  6.1、批量适配器的封装

  我们在项目中,可能需要对一批的旧系统的接口进行封装,这个时候我们可以通过配置文件的方式配置适配器。

  例如我们上面的查询,可能我现在对于XML文件的查询方法与数据库的查询方法2个旧的查询服务进行封装,然后我在实际的项目中,通过配置来选择我使用哪个查询方法完成查询服务,通过传入参数,或者是配置节信息来进行控制。我们来看看相关的示例代码:

旧系统定义的查询服务接口:
public interface IQuery
{
object Query();
}
XML查询和数据库方式的实现:
public class XMLQuery : IQuery
{
public object Query()
{
throw new NotImplementedException();
}
}
public class DbQuery : IQuery
{
public object Query()
{
throw new NotImplementedException();
}
}
新查询服务接口:
public interface ISelect
{
object GetList();
}
具体的适配器代码实现:
public class XMLAdapter : ISelect
{
private XMLQuery query = new XMLQuery();
public object GetList()
{
return query.Query();
}
}
public class DbAdapter : ISelect
{
private DbQuery query = new DbQuery();
public object GetList()
{
return query.Query();
}
}
工厂来负责创建旧系统接口的服务的对象:
public class AdapterFactory
{
public static ISelect CreateAdapter()
{
return (ISelect)Activator.CreateInstance(Type.GetType(""));
}
}
具体的调用测试代码:
class Program
{
static void Main(string[] args)
{
ISelect select
= AdapterFactory.CreateAdapter();
object o= select.GetList();
}
}

  6.2、通用适配器

旧系统定义的查询服务接口:
public interface IQuery
{
object Query();
}
XML查询和数据库方式的实现:
public class XMLQuery : IQuery
{
public object Query()
{
throw new NotImplementedException();
}
}
public class DbQuery : IQuery
{
public object Query()
{
throw new NotImplementedException();
}
}
工厂来负责创建旧系统接口的服务的对象:
public class OldFactory
{
public static IQuery CreateQuery()
{
return (IQuery)Activator.CreateInstance(Type.GetType(""));
}
}
新查询服务接口:
public interface ISelect
{
object GetList();
}
具体的通用适配器代码实现:
public class ComAdapter : ISelect
{
IQuery query
= OldFactory.CreateQuery();

public object GetList()
{
return query.Query();
}
}
将适配器的创建过程通过工厂来实现,达到解耦的目的:
public class AdapterFactory
{
public static ISelect CreateAdapter()
{
return new ComAdapter ();
}
}
具体的调用测试代码:
class Program
{
static void Main(string[] args)
{
ISelect select
= AdapterFactory.CreateAdapter();
object o= select.GetList();
}
}

  七、适配器模式使用总结

  我们上面给出了适配器模式的简单讲解,其实适配器模式的应用还是很广泛的,上面也分析了适配器模式的使用场景和特点,那么其实本篇还没有给出实例讲述适配器之间的转换:         

  上面我们讲述了2中比较通用的形式来调用适配器,还有其他的方式,比如通过字典的方式,然后通过属性索引的形式来使用适配器,我上面给出了一些比较简单的通用的使用思路,当然还有很多更好的方式,希望大家指出,向大伙学习了。我们这里给出适配器之间相互转换的情况,有的时候,我们发现2个适配器之间也需要进行相应的转配,例如我们上面的数据库和XML文件的查询接口,例如有的时候,我需要把XML文件的数据转换到数据库中,或者把数据库中的数据保存成XML形式,这个时候,我们就需要定义一个对象,来完成相应的适配器之间的适配。

image  通过转配器来完成适配器到适配器之间的转换。具体的代码实现,这里暂不给出了,下篇会讲桥模式的时候,会给出这部分的具体实现,还请关注!我相信通过上面的讲述,大家对这个适配器模式有了一定的映像,我们上面没有讲述类适配器和对象适配器之间的区别,这里补充讲解一下:

  对象适配器:不是通过继承的方式,而是通过对象组合的方式来进行处理的,我们只要学过OO的设计原则的都知道,组合相比继承是推荐的方式。

      类适配器:通过继承的方式来实现,将旧系统的方法进行封装。对象适配器在进行适配器之间的转换过程中,无疑类适配器也能完成,但是依赖性会加大,并且随着适配要求的灵活性,可能通过继承膨胀的难以控制。

      一般来说类适配器的灵活性较差,对象适配器较灵活,是我们推荐的方式,可以通过依赖注入的方式,或者是配置的方式来做。类适配器需要继承自要适配的旧系统的类,无疑这不是一个好的办法。

  本文Demo下载

0
0

软件设计热门文章

    软件设计最新文章

      最新新闻

        热门新闻