c#设计模式(6)——适配器模式
一、引言
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
接下来要说个例子来演示适配器模式的使用。其中我们一直在使用sqlserver进行增删查改的操作,突然某一天,感觉性能不行了,想替换成redis这种nosql的增删查改的方式,但是redis的帮助类的并没有和sqlserver查询类的接口命名一致,直接替换成本大,这时就需要一个中间层来适配,使得原来sqlserver的数据库操作无缝对接redis数据库操作。
二、介绍
2.1 定义
下面让我们看看适配器的定义,适配器模式——把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。适配器模式有类的适配器模式和对象的适配器模式两种形式,下面我们先来描述一下类适配器模式。
2.2 类适配器
1. 在说适配器前,先展示一下sqlserver帮助类的实现。首先,先定义统一的增删查改帮助类接口。
/// <summary>
/// sql帮助抽象类
/// </summary>
public interface IHelper
{
void Query<T>();
void Add<T>();
void Update<T>();
void Delete<T>();
}
2.接着就是sqlserver帮助类实现IHelper接口.
public class SqlServerHelper : IHelper
{
public SqlServerHelper()
{
Console.WriteLine($"{this.GetType().Name} 被构造");
}
public void Add<T>()
{
Console.WriteLine($"{this.GetType().Name}的Add正在添加数据");
}
public void Delete<T>()
{
Console.WriteLine($"{this.GetType().Name}的Delete正在删除数据");
}
public void Query<T>()
{
Console.WriteLine($"{this.GetType().Name}的Query正在查询数据");
}
public void Update<T>()
{
Console.WriteLine($"{this.GetType().Name}的Update正在更新数据");
}
}
3.sqlserver一直用得好好的,现在业务升级了,数据库撑不住了,关系型数据库性能堪忧,Redis这种nosql很好,但是有个问题Redis有自定义的帮助类,如果需要升级使用Redis,不能直接替换sqlserver的帮助类的接口方法;因为RedisHelper没有实现IHelper接口;遇到一个想要放一起使用但是却不能一起使用的问题。这时我们的适配器就要登场了,先演示一下类适配器。
/// <summary>
/// redis帮助类,由于执行方法与sql的执行方法不一致,需要适配
/// </summary>
public class RedisHelper
{
public RedisHelper()
{
Console.WriteLine($"{this.GetType().Name} 被构造");
}
public void RedisAdd<T>()
{
Console.WriteLine($"{this.GetType().Name}的RedisAdd正在添加数据");
}
public void RedisDelete<T>()
{
Console.WriteLine($"{this.GetType().Name}的RedisDelete正在删除数据");
}
public void RedisQuery<T>()
{
Console.WriteLine($"{this.GetType().Name}的RedisQuery正在查询数据");
}
public void RedisUpdate<T>()
{
Console.WriteLine($"{this.GetType().Name}的RedisUpdate正在更新数据");
}
}
/// <summary>
/// 类适配器
/// </summary>
public class RedisClassHelper : RedisHelper, IHelper
{
// 继承实现了让IHelper 和Redis不兼容的事儿---适配器的一种;
// 继承:
// 1.因为是强继承,具有侵入性
// 2.RedisClassHelper只能为RedisHelper服务;
public void Add<T>()
{
base.RedisAdd<T>();
}
public void Delete<T>()
{
base.RedisDelete<T>();
}
public void Query<T>()
{
base.RedisQuery<T>();
}
public void Update<T>()
{
base.RedisUpdate<T>();
}
}
class Program
{
static void Main(string[] args)
{
// sqlserver查询
IHelper sqlServerHelper = new SqlServerHelper();
sqlServerHelper.Add<DesignPatternStructure>();
sqlServerHelper.Update<DesignPatternStructure>();
sqlServerHelper.Query<DesignPatternStructure>();
sqlServerHelper.Delete<DesignPatternStructure>();
//现在业务升级了,数据库撑不住了,关系型数据库性能堪忧
//Nosql == Redis很好----Redis的帮助类库--ServiceStack
//需要升级使用Redis;----不能直接换了;因为RedisHelper没有实现IHelper接口;
//遇到一个想要放一起使用但是却不能一起使用的问题;
//这时就需要一个适配器了
//类适配器
//继承实现了让IHelper 和Redis不兼容的事儿---适配器的一种;
//继承:
//1.因为是强继承,具有侵入性
//2.RedisClassHelper只能为Redishelper服务;
IHelper redisClassHelper = new RedisClassHelper();
redisClassHelper.Add<DesignPatternStructure>();
redisClassHelper.Update<DesignPatternStructure>();
redisClassHelper.Query<DesignPatternStructure>();
redisClassHelper.Delete<DesignPatternStructure>();
}
}
2.2 对象适配器
4. 以上就是类适配器的实现,但是大家都发现了一个问题,就是虽然解决RedisHelper和IHelper不兼容的问题,但是因为是强继承,具有侵入性RedisClassHelper只能为Redishelper服务,而且想要匹配一 个类以及所有它的子类时,类的适配器模式就不能胜任了;为了解决这个问题,多了一种对象适配器,使得适配类可以兼容多个不同的对象。
为了证明这一点,我写一个继承了RedisHelper类的子类
public class RedisChildHelper: RedisHelper
{
}
然后我写个对象适配器
/// <summary>
/// 对象适配器
/// </summary>
public class RedisObjHelper : IHelper
{
private RedisHelper _redisHelper = null;
/// <summary>
/// 构造函数方式注入
/// 在实例化的时候,必须传入----就可以保障需要适配的对象不会为null
/// </summary>
/// <param name="redisHelper"></param>
public RedisObjHelper(RedisHelper redisHelper)
{
_redisHelper = redisHelper;
}
public void SetRedisHelper(RedisHelper redisHelper)
{
_redisHelper = redisHelper;
}
public void Add<T>()
{
_redisHelper.RedisAdd<T>();
}
public void Delete<T>()
{
_redisHelper.RedisDelete<T>();
}
public void Query<T>()
{
_redisHelper.RedisQuery<T>();
}
public void Update<T>()
{
_redisHelper.RedisUpdate<T>();
}
}
5.演示一下对象适配器的实现
class Program
{
static void Main(string[] args)
{
//对象适配器
//为什么说组合优于继承呢?
//1.没有侵入性
//2.可以为多个类型服务
//3.相对来说要更加灵活一点
//IHelper redisObjHelper = new RedisObjHelper(new RedisHelper());
IHelper redisChildHelper = new RedisObjHelper(new RedisChildHelper());
redisObjHelper.Add<DesignPatternStructure>();
redisObjHelper.Update<DesignPatternStructure>();
redisObjHelper.Query<DesignPatternStructure>();
redisObjHelper.Delete<DesignPatternStructure>();
}
}
三、适配器模式的优缺点
类适配器模式:
1.优点:
可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”
可以重新定义(被适配的类)的部分行为.
仅仅引入一个对象,并不需要额外的字段来引用RedisHelper实例(这个即是优点也是缺点)
2.缺点:
采用了 “多继承”的实现方式,带来了不良的高耦合。
对象适配器模式:
1.优点:可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”,采用 “对象组合”的方式,更符合松耦合,以兼容多个不同的对象

浙公网安备 33010602011771号