设计模式2.Adapter模式

源码地址 https://github.com/sadgeminids/AdapterLearning

 

设计模式目的:

适配类,使得类可以作用于需要另一个类型或者接口的场景。

用通俗一点的话描述就是:你有一个A,但是某个地方需要使用B,Adapter可以帮助你把A包装成B。

举个生活中的类似场景:假如你手机是IOS的,你去朋友家,他只有安卓充电线;这个时候就需要一个转换头,将安卓的接口转换成IOS的。

 

该设计模式有两种常见实现方式:

1.通过继承方式适配

UML图(扒自 图解设计模式):

设计模式2.Adapter模式_第1张图片

模式核心概述:

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的地方,快速完成某些任务。

 

2.通过聚合(包含类对象)方式适配

UML图(扒自 图解设计模式):

设计模式2.Adapter模式_第2张图片

模式核心概述:

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;
        }
    }

 

你可能感兴趣的:(C#,设计模式,Adapter,设计模式,适配)