C#设计模式-结构型-适配器模式

适配器模式的实现要点:

在适配器模式的结构图有以下角色:

  (1)、目标角色(Target):定义Client使用的与特定领域相关的接口。

  (2)、客户角色(Client):与符合Target接口的对象协同。

  (3)、被适配角色(Adaptee):定义一个已经存在并已经使用的接口,这个接口需要适配。

  (4)、适配器角色(Adapte) :适配器模式的核心。它将对被适配Adaptee角色已有的接口转换为目标角色Target匹配的接口。对Adaptee的接口与Target接口进行适配.

  1、Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。

2、GoF23定义了两种Adapter模式的实现结构:对象适配器和类适配器。类适配器采用“多继承”的实现方式,在C#语言中,如果被适配角色是类,Target的实现只能是接口,因为C#语言只支持接口的多继承的特性。在C#语言中类适配器也很难支持适配多个对象的情况,同时也会带来了不良的高耦合和违反类的职责单一的原则,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神,对适配的对象也没限制,可以一个,也可以多个,但是,使得重定义Adaptee的行为较困难,这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。Adapter模式可以实现的非常灵活,不必拘泥于GoF23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象”作为新的接口方法参数,来达到适配的目的。

3、Adapter模式本身要求我们尽可能地使用“面向接口的编程”风格,这样才能在后期很方便地适配。

  适配器模式用来解决现有对象与客户端期待接口不一致的问题,下面详细总结下适配器两种形式的优缺点。

 1】、类的适配器模式:

     优点:

           (1)、可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”

           (2)、可以重新定义Adaptee(被适配的类)的部分行为,因为在类适配器模式中,Adapter是Adaptee的子类

           (3)、仅仅引入一个对象,并不需要额外的字段来引用Adaptee实例(这个即是优点也是缺点)。

     缺点:

           (1)、用一个具体的Adapter类对Adaptee和Target进行匹配,当如果想要匹配一个类以及所有它的子类时,类的适配器模式就不能胜任了。因为类的适配器模式中没有引入Adaptee的实例,光调用this.SpecificRequest方法并不能去调用它对应子类的SpecificRequest方法。

           (2)、采用了 “多继承”的实现方式,带来了不良的高耦合。

    2】、对象的适配器模式

         优点:

              (1)、可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”(这点是两种实现方式都具有的)

              (2)、采用 “对象组合”的方式,更符合松耦合。

        缺点:

              (1)、使得重定义Adaptee的行为较困难,这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。

 3】、适配器模式使用的场景:

          (1)、系统需要复用现有类,而该类的接口不符合系统的需求

          (2)、想要建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。

          (3)、对于对象适配器模式,在设计里需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。

对象的适配器模式

A 类中有虚拟a方法 B类中有b方法
C类继承A类,且C类中含有B类的变量对象mB
C类重写a方法,在a方法内调用变量对象mB的b方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AdapterSample
{

  


        /// <summary>
        /// 我家只有2个孔的插座,也就是适配器模式中的目标(Target)角色,这里可以写成抽象类或者接口
        /// </summary>
        public class TwoHoleTarget
        {
            // 客户端需要的方法
            public virtual void Request()
            {
                Console.WriteLine("两孔的充电器可以使用");
            }
        }

        /// <summary>
        /// 手机充电器是有3个柱子的插头,源角色——需要适配的类(Adaptee)
        /// </summary>
        public class ThreeHoleAdaptee
        {
            public void SpecificRequest()
            {
                Console.WriteLine("我是3个孔的插头也可以使用了");
            }
        }

        /// <summary>
        /// 适配器类,TwoHole这个对象写成接口或者抽象类更好,面向接口编程嘛
        /// </summary>
        public class ThreeToTwoAdapter : TwoHoleTarget
        {
            // 引用两个孔插头的实例,从而将客户端与TwoHole联系起来
            private ThreeHoleAdaptee threeHoleAdaptee = new ThreeHoleAdaptee();
            //这里可以继续增加适配的对象。。

            /// <summary>
            /// 实现2个孔插头接口方法
            /// </summary>
            public override void Request()
            {
                //可以做具体的转换工作
                threeHoleAdaptee.SpecificRequest();
                //可以做具体的转换工作
            }
        }
    
    class Program
    {
        ///<summary>
        ///家里只有两个孔的插座,也懒得买插线板了,还要花钱,但是我的手机是一个有3个小柱子的插头,明显直接搞不定,那就适配吧
        ///</summary>
        static void Main(string[] args)
        {
        //好了,现在就可以给手机充电了
        TwoHoleTarget homeTwoHole = new ThreeToTwoAdapter();
        homeTwoHole.Request();
        Console.ReadLine();


    }
    }
}

在这里插入图片描述

类的适配器模式

接口A 类中有a方法 抽象 B类中有b方法
C类继承A类和B类,C类实现a方法,在a方法内调用来至于继承B的b方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AdapterSample
{


        /// <summary>
        /// 我家只有2个孔的插座,也就是适配器模式中的目标角色(Target),这里只能是接口,也是类适配器的限制
        /// </summary>
        public interface ITwoHoleTarget
        {
            void Request();
        }

        /// <summary>
        /// 3个孔的插头,源角色——需要适配的类(Adaptee)
        /// </summary>
        public abstract class ThreeHoleAdaptee
        {
            public void SpecificRequest()
            {
                Console.WriteLine("我是三个孔的插头");
            }
        }

        /// <summary>
        /// 适配器类,接口要放在类的后面,在此无法适配更多的对象,这是类适配器的不足
        /// </summary>
        public class ThreeToTwoAdapter : ThreeHoleAdaptee, ITwoHoleTarget
        {
            /// <summary>
            /// 实现2个孔插头接口方法
            /// </summary>
            public void Request()
            {
                // 调用3个孔插头方法
                this.SpecificRequest();
            }
        }
   

    class Program
    {
        ///<summary>
        ///家里只有两个孔的插座,也懒得买插线板了,还要花钱,但是我的手机是一个有3个小柱子的插头,明显直接搞不定,那就适配吧
        ///</summary>
        static void Main(string[] args)
        {
            //好了,现在可以充电了
            ITwoHoleTarget change = new ThreeToTwoAdapter();
            change.Request();
            Console.ReadLine();


        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值