Apater适配器模式(结构型模式)

1、概要

适配:即在不改变原有实现的基础上,将原先不适合的接口转换成适合的接口.

what is Apater?适配,这个概念在生活中无处不在,比如你的iphone 4手机充电器坏了,这是时候只有一个iphone 8的充电器,两个充电器的头并不匹配,这个时候,你就需要一个充电器适配器.这个适配器将8的充电器转换成能支持4充电的充电器接口.这个例子在不改变8的充电器原有功能的情况下,将8不适合4的接口通过适配器转变成合适的接口.等等例子还有很多.

2、动机

在软件开发的过程中,常常需要将一些"现存的对象"放到新的环境中去,但是新的环境接口,这些对象并不满足.如何解决这种"迁移的变化",就是适配器模式要解决的问题.

3、意图

将已经稳定的一个类的接口转换成客户需要的接口,Apater模式使用原本由于接口不兼容的而不能一起工作的接口能一起工作.

4、代码实例-对象适配器

现在客户系统在实现一个功能的时候只需要ArrayList的部分功能,需要的功能通过ICustomerReqiured接口定义.这个时候.用适配器模式能很好的解决这个问题!

        /// <summary>
        /// 客户要求的接口
        /// </summary>
        public interface ICustomerRequired
        {
            void Push(object item);

            object Pop();

            object Peek();
        }

        /// <summary>
        /// 对象适配器
        /// 对象适配器,Apater创建了一个ArrayList的包装器,缩小了ArrayList的接口范围,如果有特殊的业务需要使用ArrayList的部分方法,可以使用该模式
        /// </summary>
        public class Apater : ICustomerRequired
        {
            private ArrayList _apatee;//需要被适配的对象,也是存在的稳定的对象

            public Apater(ArrayList arrayList)
            {
                _apatee = arrayList;
            }

            /// <summary>
            /// 返回最后一项
            /// </summary>
            /// <returns></returns>
            public object Peek()
            {
                if (_apatee.Count >= 1)
                    return _apatee[_apatee.Count - 1];
                return null;
            }

            /// <summary>
            /// 移除最后一项,返回最后一项
            /// </summary>
            /// <returns></returns>
            public object Pop()
            {
                _apatee.RemoveAt(_apatee.Count - 1);
                return Peek();
            }

            /// <summary>
            /// 添加一项
            /// </summary>
            /// <param name="item"></param>
            public void Push(object item)
            {
                _apatee.Add(item);
            }
        }

当然,失配器远比上面代码所展示的功能要强,不仅仅支持缩小限制ArrayList的功能,也能扩展、修改组合ArrayList的功能.

5、代码实例-类适配器

        /// <summary>
        /// 类适配器
        /// 类适配器,Apater继承了ArrayList,拥有了ArrayList类所有方法的同时,有实现客户要求的接口,但是违反了类职责单一的oop原则
        /// </summary>
        public class Apater :ArrayList,ICustomerRequired
        {

            public Apater(ICollection collection) : base(collection)
            {

            }
            /// <summary>
            /// 返回最后一项
            /// </summary>
            /// <returns></returns>
            public object Peek()
            {
                if (Count >= 1)
                    return this[this.Count - 1];
                return null;
            }

            /// <summary>
            /// 移除最后一项,返回最后一项
            /// </summary>
            /// <returns></returns>
            public object Pop()
            {
                this.RemoveAt(this.Count - 1);
                return Peek();
            }

            /// <summary>
            /// 添加一项
            /// </summary>
            /// <param name="item"></param>
            public void Push(object item)
            {
                this.Add(item);
            }
        }

分析上面的代码发现,虽然Apater很好的完成了需求,但是存在以下两个缺点:

1、违背了OOP原则一类的单一职责,Apater即有ArrayList的职责,又包含了ICustomerRequired接口的职责.这种方式的适配器不建议使用,更建议使用对象适配器!

2、类只能单继承,当适配器需要适配多个类时,类适配器就无法完成这个任务.

3、类之间的强耦合关系(在OOP中,继承会自带耦合效果),当被适配的类发生改变时,当前适配器会被强加这种改变.

所以,使用类适配器需要慎重.相比类适配器更推荐第一种对象适配器.

6、关于适配器模式的设计建议

客户端调用,优先使用客户要求的接口类,如下代码:

    /// <summary>
    /// 第三方调用系统
    /// </summary>
    public class ThirdSystem
    {
        /// <summary>
        /// 建议这种调用方式,更符合OOP的思想
        /// </summary>
        /// <param name="customerRequired"></param>
        public void Process(ICustomerRequired customerRequired)
        {

        }

        /// <summary>
        /// 不建议这种方法
        /// </summary>
        /// <param name="apater"></param>
        public void ProcssError(Apater apater)
        {

        }
    }

上面的代码更加符合面向接口的编程思想.

7、.Net Framework中使用适配器模式的案例

        public class User
        {
            public string Name { get; set; }

            public int Age { get; set; }
        }

        /// <summary>
        /// IComparer<User> 为客户程序要求适配器实现的接口,必须实现该接口,完成对两个User实例的年龄比较
        /// </summary>
        public class UserCompareApater : IComparer<User>
        {
            /// <summary>
            /// User类作为被适配对象
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public int Compare(User x, User y)
            {
                if (x.Age > y.Age)
                    return 1;
                else if (x.Age < y.Age)
                    return -1;
                return 0;
            }

通过适配器,继承了FCL中提供的两个类型比较的接口,实现了对两个User实例的排序。

其它的例子还有很多.如.Net数据库访问类(Apater变体),主流的数据库都没有提供DataSet接口,但是使用DbDataApater可以访问各种数据库,并且将读取过来的数据填充到DataSet实例中.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏架构师之旅

轻松学习设计模式之面向对象的设计原则

对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决...

913
来自专栏斑斓

运用Aggregator模式实现MapReduce

《基于Actor的响应式编程》计划分为三部分,第一部分剖析响应式编程的本质思想,为大家介绍何谓响应式编程(Reactive Programming)。第二部分则...

3306
来自专栏Android开发经验

ExpandableStickyListHeadersListView遇到的一个问题

1394
来自专栏码匠的流水账

java降低竞争锁的一些方法

本文介绍一下提升并发可伸缩性的一些方式:减少锁的持有时间,降低锁的粒度,锁分段、避免热点域以及采用非独占的锁或非阻塞锁来代替独占锁。

961
来自专栏racaljk

关于llvm kaleidoscope: 记一次Debug血泪之路

简而言之,慎(bu)用(yong)全局变量!                                

1151
来自专栏腾讯NEXT学位

提升代码可读性的 10 个技巧

3676
来自专栏牛客网

热乎乎的阿里面经,攒人品

一面: 1.自我介绍一下,然后问你最擅长哪一方面(我说虚拟机、集合) 2.他说HashMap我现在都不敢问了,出过很多笑话,很多人都是背的,自己没办法判断是看...

3495
来自专栏Linyb极客之路

工作流引擎之activiti6实时流程图追踪

有接触过activiti的朋友可能知道,在activiti5.x的追踪流程节点查找,可以用

2.4K2
来自专栏个人分享

Flink单机版安装与wordCount

Flink为大数据处理工具,类似hadoop,spark.但它能够在大规模分布式系统中快速处理,与spark相似也是基于内存运算,并以低延迟性和高容错性主城,其...

1241
来自专栏我是攻城师

Java高级软件工程师面试考纲

2904

扫码关注云+社区