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實例中.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章