源码地址 https://github.com/sadgeminids/AdapterLearning
适配类,使得类可以作用于需要另一个类型或者接口的场景。
用通俗一点的话描述就是:你有一个A,但是某个地方需要使用B,Adapter可以帮助你把A包装成B。
举个生活中的类似场景:假如你手机是IOS的,你去朋友家,他只有安卓充电线;这个时候就需要一个转换头,将安卓的接口转换成IOS的。
该设计模式有两种常见实现方式:
UML图(扒自 图解设计模式):
1.接口Target Interface(图中Print接口),是目标场景需要的目标接口
2.源对象类Source Class(图中Banner),是开始拥有的自有类
3.适配对象Adatper Class(图中PrintBanner),是将Source Class 适配符合Target Interface的类型
1.接口Target Interface
public interface TargetInterface
{
void OnGUI();
}
接口功能很简单,就是在屏幕上绘制一些元素;
2.源对象类Source Class
public class SourceClass
{
public void ShowButton()
{
Console.WriteLine("Source class show button");
}
}
源对象呢,提供的方法则是绘制一个Button按钮。都是在屏幕上做某些事情,但是因为项目不同,负责人不同,等等原因,导致接口不统一。这时候我们需要一个适配对象来统一一下接口。
3.适配对象Adatper Class
public class AdapterByInterface : SourceClass, TargetInterface
{
public void OnGUI()
{
ShowButton();
}
}
这个适配对象继承了Source Class,所以它拥有Source Class的一切功能。然后又实现了Target Interface,使得它也有了Target Interface的特征。
这样我们在需要Target Interface的地方都可以使用它,并且内部处理后可以使得它能够用Source Class提供的方法去完成Target Interface所需要做的任务。
调用方式
class Program
{
static void Main(string[] args)
{
AdapterByInterface ad = new AdapterByInterface();
// To do something with ad ...
TargetInterface tInterface = ad;
tInterface.OnGUI();
}
}
就这样,通过继承类+接口的方式,我们使得A可以应用到需要B的地方,快速完成某些任务。
UML图(扒自 图解设计模式):
1.类Target Class(图中Print接口),是目标场景需要的目标类
2.源对象类Source Class(图中Banner),是开始拥有的自有类
3.适配对象Adatper Class(图中PrintBanner),是将Source Class 适配符合Target Class的类型
看起来类图以及描述都很相似?其实是有本质区别的。最大的不同点在于上一种实现方式适配对象是继承自SourceClass,而这一种实现方式适配对象Adatper Class不再继承SourceClass,而是包含一个SourceClass的对象。看代码可能更直观。
1. Target Class
public class TargetClass
{
public virtual void OnGUI()
{
}
}
目标对象从一个接口变成了类,包含虚函数
2.Source Class
public class SourceClass
{
public void ShowButton()
{
Console.WriteLine("Source class show button");
}
}
源对象没有任何改变
3.适配对象Adatper Class
public class AdapterByClass : TargetClass
{
SourceClass m_source;
public AdapterByClass(SourceClass sc)
{
m_source = sc;
}
public override void OnGUI()
{
m_source.ShowButton();
}
}
可以看到Adatper Class 中包含了一个Source Class 的对象SourceClass m_source。后续的工作是通过这个类对象来完成的。
4.调用方式
class Program
{
static void Main(string[] args)
{
SourceClass sc = new SourceClass();
// To do something with sc
TargetClass tClass = new AdapterByClass(sc);
tClass.OnGUI();
Console.ReadKey();
}
}
仅就C#而言,如果有认真看代码的话,可以发现造成这种区别的原因在于Target的类型到底是类还是接口。因为要让我们的适配对象能应用于Target所在的环境,那就必须继承Target。这样就会出现以下情况:
1.Target如果是接口,Adapter对象继承接口之外,还可以继承自SourceClass获得行为
2.Target如果是类,Adapter继承了类后,无法再继承另一个类(SourceClass)
实现方式不同,但目标都是一致的,同样是为了让 Source --> Target 这个转换成立。
我们在实现逻辑时,遇见类型不一致的情况非常普遍。尤其是在接收到网络消息后,要把服务器的数据结构转换为客户端的结构。这种场景下,如果每个数据结构都要去实现一个类做这种事情,其实是有点得不偿失的。
毕竟,Adapter模式更适合在跨项目、跨部门合作,提供第三方组件、通用接口等场景下应用起来更得心应手。而在自己完全控制整个逻辑的情形下,弄个辅助函数做类似的事情效率来得更高:
public class GameSourceClass
{
public int Hp;
public int Mp;
public int Attack;
}
public class GameTargetClass
{
public int Attack;
}
public class LocalConvertHelper
{
public static GameTargetClass ConvertSourceToTarget(GameSourceClass sc)
{
GameTargetClass tc = new GameTargetClass();
tc.Attack = sc.Attack;
return tc;
}
}