1. 程式人生 > >設計模式-適配者模式

設計模式-適配者模式

在幾年前,有記者問姚明說:在CBA和NBA的最大的區別是什麼?姚明的答案是'NBA我需要翻譯,而在CBA我不需要。'經過四年的NBA錘鍊,他的確是在NBA成長了。不但球技大漲,英語也學得非常棒,用英文答記者問一點問題都沒有,不得不令人佩服啊。

姚明剛去美國時,怎麼打球呢?什麼都聽不懂。之前專門為他配備了翻譯的,那個翻譯一直在姚明身邊,特別是比賽場上,教練、隊員與他的對話全部是通過翻譯來溝通。

介面卡模式:講一個類的介面轉換成客戶希望的另外一個藉口,Adapter模式使得原本由於藉口不相容而不能一起工作的那些類可以一起工作。

介面卡模式主要解決什麼問題呢?需要的東西就在面前,但卻不能使用,而短時間又無法改造它,於是我們就想辦法適配他。

姚明不會英語,讓姚明立刻會說英語不太可能,讓教練和球員會說中文更難辦了,那就找個翻譯。翻譯就是介面卡。

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

namespace Adapter
{
    //球員
    abstract class Player
    {
        protected string name;

        public Player(string name)
        {
            this.name = name;
        }
        //進攻和防守方法
        public abstract void Attack();
        public abstract void Defense();
    }
    //前鋒
    class Forwards : Player
    {
        public Forwards(string name)
            : base(name)
        {
        }

        public override void Attack()
        {
            Console.WriteLine("前鋒 {0} 進攻", name);    
        }

        public override void Defense()
        {
            Console.WriteLine("前鋒 {0} 防守", name);    
        }
    }
    //中鋒
    class Center : Player
    {
        public Center(string name)
            : base(name)
        {
        }

        public override void Attack()
        {
            Console.WriteLine("中鋒 {0} 進攻", name);    
        }

        public override void Defense()
        {
            Console.WriteLine("中鋒 {0} 防守", name);    
        }
    }
    //後衛
    class Guards : Player
    {
        public Guards(string name)
            : base(name)
        {
        }

        public override void Attack()
        {
            Console.WriteLine("後衛 {0} 進攻", name);    
        }

        public override void Defense()
        {
            Console.WriteLine("後衛 {0} 防守", name);    
        }
    }
    //外籍中鋒
    class ForeignPlayer
    {
        //外籍中鋒類球員的姓名故意用屬性而不是構造方法來區別前三個球員類的不同
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        //表明外籍中鋒只懂得中文進攻
        public void 進攻()
        {
            Console.WriteLine("外籍中鋒 {0} 進攻", name);
        }
        //表明外籍中鋒只懂得中文防守
        public void 防守()
        {
            Console.WriteLine("外籍中鋒 {0} 防守", name);
        }
    }
    //翻譯者類
    class Translator : Player
    {
        //宣告並例項化一個內部外籍中鋒物件,表明翻譯者與外籍球員有關聯
        private ForeignPlayer wjzf = new ForeignPlayer();

        public Translator(string name)
            : base(name)
        {
            wjzf.Name = name;
        }
        //翻譯者講Attack翻譯為進攻告訴外籍中鋒
        public override void Attack()
        {
            wjzf.進攻();
        }
        //翻譯者講Defense翻譯為防守告訴外籍中鋒
        public override void Defense()
        {
            wjzf.防守();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Player b = new Forwards("巴蒂爾");
            b.Attack();
            Player m = new Guards("麥克格雷迪");
            m.Attack();
            //翻譯者告訴姚明,教練要求你既要進攻,又要防守。
            Player ym = new Translator("姚明");
            ym.Attack();
            ym.Defense();

            Console.Read();
        }
    }
}

系統的資料和行為都正確,但介面不符時,我們應該考慮用介面卡,目的是使控制範圍之外的一個原有物件與某個藉口匹配、介面卡模式主要應用於希望複用一些現存的類,但是介面又與複用環境要求不一致的情況。介面卡模式講了兩種型別,類介面卡模式和物件介面卡模式。主要講的是物件介面卡。

何時使用介面卡模式呢?

在想使用一個已經存在的類,但如果它的介面,也就是他的方法和你的要求不相同時,應該考慮介面卡模式。

兩個類所做的事情相同或相似,但是具有不同的介面時要使用它。客戶程式碼統一呼叫同一藉口就行了。可以更簡單,更直接,更緊湊。

要在雙方都不太容易修改的時候再使用介面卡模式適配。

介面卡模式在.Net中應用:DataAdapter用作DataSet和資料來源之間的介面卡以便檢索和儲存資料。DataAdapter通過對映Fill(這更改了DataSet中的資料以便與資料來源中的資料相匹配)和Update(這更改了資料來源中的資料以便與DataSet中的資料相匹配)來提供這一介面卡。

介面卡模式雖好,卻不可亂用。亂用不如不用。

當年,魏文王問名醫扁鵲說,你們兄弟三人,都精於醫術,到底是哪一位最好呢?扁鵲答:長兄最好,中兄次之,我最差。文王再問:那麼為什麼你最出名呢?扁鵲答:長兄治病,是治病於病情發作之前。由於一般人不知道他事先能剷除病因,所以他的名氣無法傳出去。中兄治病,是治病於病情初起時,一般人認為他只能治輕微的小病,所以他的名氣只及本鄉里。而我是治病於病情嚴重之時。所以大家以為扁鵲醫術最高。

如果能事先預防藉口不同的問題,不匹配問題就不會發生,在有小的介面不統一問題發生時,及時重構問題不至於擴大,只有碰到無法改變原有設計和程式碼的情況時,才考慮匹配。事後控制不如事中控制,事中控制不如事前控制。