1、引言
在实际的开发过程中,由于应用环境的变化(例如使用语言的变化),我们需要的实现在新的环境中没有现存对象可以满足,但是其他环境却存在这样现存的对象。那么如果将“现存的对象”在新的环境中进行调用呢?解决这个问题的办法就是我们本文要介绍的适配器模式——使得新环境中不需要去重复实现已经存在了的实现而很好地把现有对象(指原来环境中的现有对象)加入到新环境来使用。
2、适配器模式详细介绍
“在GoF的设计模式中,对适配器的模式讲了两种类型,类适配器模式和对象适配器模式,由于类适配器模式通过多重继承对一个接口与另一个接口进行匹配,而C#、VB.Net、Java等语言都不支持多重继承(C++支持),也就是一个类只有一个父类,所以我们这里主要讲的是对象适配器。”
2.1、定义
- 适配器模式(Adapter Pattern):
下面让我们看看适配器的定义,适配器模式——把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。
2.2、目的
该模式的目的是使受控制范围之外的一个原有对象与某个接口匹配
2.3、解决的问题
解决了在软件开发中,也就是系统的数据和行为都正确,但接口不符的问题。
2.4、模式的原理
下面时该模式的UML类图:
从上图可知,状态者模式涉及以下三个角色:
- 客户端所期待的接口(Target类):客户端所期待的接口(目标),目标可以是具体的或抽象的类,也可以是接口;
- 需要适配的类(Adaptee类):需要去转化适配的类;
- 适配器(Adapter类):适配器通过在内部包装一个Adapter对象,把原接口转换成目标接口。
2.5、类图实现
详细代码如下:
Target类(客户端所期待的接口)
/// <summary>
/// 客户端所期待的接口。
/// 目标可以是具体的或抽象的类,也可以是接口
/// </summary>
class Target
{
public virtual void Request()
{
Console.WriteLine("普通请求...");
}
}
Adaptee类(需要适配的类)
/// <summary>
/// 需要适配的类
/// </summary>
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("特殊请求...");
}
}
Adapter类(适配器)
/// <summary>
/// 通过在内部包装一个Adapter对象,把原接口转换成目标接口
/// </summary>
class Adapter : Target
{
/// <summary>
/// 建立一个私有的Adaptee对象
/// </summary>
private Adaptee adaptee = new Adaptee();
/// <summary>
/// 这样就可以把表面上调用Request()的方法
/// 变成实际调用SpecificRequest()的方法
/// </summary>
public override void Request()
{
adaptee.SpecificRequest();
}
}
测试代码如下:
Target target = new Adapter();
target.Request();
测试结果如下:
特殊请求...
3、适配器模式优缺点
对象的适配器模式的优缺点如下:
- 优点:
- 可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”(这点是两种实现方式都具有的)
- 采用 “对象组合”的方式,更符合松耦合。
- 缺点:
- 使得重定义Adaptee的行为较困难,这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。
4、适配器模式适用场景
在以下情况下可以考虑使用适配器模式:
- 系统需要复用现有类,而该类的接口不符合系统的需求
- 想要建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
- 对于对象适配器模式,在设计里需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。
5、应用举例(unity)
- 场景:打印一个学生的姓名和学号
- 具体实现代码如下:
为了方便我们把这些接口和类都写在同一个脚本里
using UnityEngine;
public class Test : MonoBehaviour {
// Use this for initialization
void Start () {
Student s = new Student();
s.Name = "张三";
s.StudentId = "10";
IPerson per = s;
per.Show(s.Name);
IStudent stu = s;
stu.Show(s.StudentId);
}
}
public interface IPerson
{
string Name
{
get;
set;
}
void Show(string name);
}
public interface IStudent
{
string StudentId
{
get;
set;
}
void Show(string studentid);
}
public class Student : IPerson, IStudent
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
private string _studentid;
public string StudentId
{
get
{
return _studentid;
}
set
{
_studentid = value;
}
}
//显式实现接口
void IPerson.Show(string name)
{
Debug.Log("姓名为:" + name);
}
//显式实现接口
void IStudent.Show(string studentid)
{
Debug.Log("学号为:" + studentid);
}
}
只需把脚本挂在摄像机上即可,测试结果如下:
6、总结
到这里适配器模式的介绍就结束了,在适配器模式中,适配器可以是抽象类,适配器模式的实现是非常灵活的,我们完全可以将Adapter模式中的“现存对象”作为新的接口方法参数,适配器类可以根据参数参数可以返回一个合适的实例给客户端。
7、unity工程下载
在文章的最后我们给出上述例子的工程下载链接,方便朋友们探讨交流!本次演示版本Unity5.6.3f1(64-bit),VS2015由于栗子比较简单这里就不提供下载了。
The End
好了,今天的分享就到这里,如有不足之处,还望大家及时指正,随时欢迎探讨交流!!!
喜欢的朋友们,请帮顶、点赞、评论!您的肯定是我写作的不竭动力!
相关阅读
C# 23种设计模式(unity演示)