文章出處

問題的提出
定義:開發一個應用,使不同型號的打印機都能與電腦連接
上下文(環境):為了滿足需求,公司現在購置了兩類打印機,即打印機A和打印機B,它將與公司1000名員工的電腦連接,實現通信。并且公司在以后可能還會購買第三類打印機。
分析上述問題,可能有如下方案
方案一:分別定義PrintA和PrintB兩個類。實現各自的Receive和Print方法,這么一來總共需要寫四個方法。這種方法應該是最直觀,最容易讓人想到的。
方案二:定義抽象類Printer,在里面寫虛方法 Receive和 Print,使得這兩臺打印機分別繼承此抽象類,并重寫 Receive和Print方法。Computer類中包含一個類型為 Printer的成員變量,并為其編寫get/set器,這樣 Computer中只需要兩個方法: ReceiveData和 PrintData,并通過多態性實現不同移動設備的讀寫。這種方法應該是接著會被想到的方法。
方案三:與方案二基本相同,只是不定義抽象類,而是定義接口I Printer,修改打印機類。Computer中通過依賴接口IPrinter實現多態性。
       現在我們來分析一下上面三種方法。首先第一種方法最為直白,實現起來最簡單,但是它有一個致命的弱點:可擴展性差。當將來有了第三中類型的打印機時,必須對Computer進行修改。這就如在一個真實的計算機上,為每一種打印機設備實現一個不同的插口、并分別有各自的驅動程序。當有了一種新的打印機設備后,我們就要將計算機大卸八塊,然后增加一個新的插口,在編寫一套針對此新設備的驅動程序。這種設計顯 然不可取。

  此方案的另一個缺點在于,冗余代碼多。在題目所給的環境中,已經說明打印機將與1000臺電腦連接,這么一來,總共就需要寫四千中方法。代碼的重復量是相當大的。我們再來看方案二和方案三,之所以將這兩個方案放在一起討論,是因為他們基本是一個方案(從思想層面上來說),只不過實現手段不同,一個是使用了抽象類,一個是使用了接口,而且最終達到的目的應該是一樣的。

  我們先來評價這種方案:首先它解決了代碼冗余的問題,因為可以動態替換打印機,并且都實現了共同的接口,所以不管有多少種移不同類型的打印機,只要一個 Receive方法和一個Print方法,多態性就幫我們解決問題了。而對第一個問題,由于可以運行時動態替換,而不必將打印類編碼在Computer 中,所以有了新的第三方設備,完全可以替換進去運行。這就是所謂的“依賴接口,而不是依賴于具體類”。如此一來,Computer和打印機類的耦合度大大下降。

我們先來看一段斷碼:

1.定義一個接口

namespace _1.InterfaceTest

{

     /// <summary>

     /// 定義打印機接口,不同類型的打印機都有共同的屬性

     /// 他們都會接受電腦的信息(Receive)并且執行打印命令(Print)。

     /// </summary>

     public interface IPrinter

     {

        void Receive();

        void Print();

     }

}

2. 實現打印機類

namespace _1.InterfaceTest

{

  /// <summary>
    /// 實現A類打印機
    /// </summary>
    public class PrinterA : IPrinter
    {
        /// <summary>
        /// 實現接口定義的Receive方法
        /// </summary>
        public void Receive()
        {
            Console.WriteLine("PrinterA  receive message from Computer……");
            Console.WriteLine("Receive finished!");
        }
        /// <summary>
        ///  實現接口定義的Print方法
        /// </summary>
        public void Print()
        {
            Console.WriteLine("PrinterA execute the Computer command ……");
            Console.WriteLine("Print finished!");
        }
    }
    /// <summary>
    /// 實現B類打印機
    /// </summary>
    public class PrinterB : IPrinter
    {
        /// <summary>
        /// 實現接口定義的Receive方法
        /// </summary>
        public void Receive()
        {
            Console.WriteLine("PrinterB  receive message from Computer……");
            Console.WriteLine("Receive finished!");
        }
        /// <summary>
        ///  實現接口定義的Print方法
        /// </summary>
        public void Print()
        {
            Console.WriteLine("PrinterB execute the Computer command ……");
            Console.WriteLine("Print finished!");
        }
    }
}
3. 實現computer類

namespace _1.InterfaceTest

{

  /// <summary>
    /// 電腦與打印機連接,不論是何種打印機,電腦都將調用這兩個方法
    /// </summary>
    public class Computer
    {
        /// <summary>
        /// 定義接口類型的變量
        /// </summary>
        private IPrinter _print;
        public IPrinter Print
        {
            get
            {
                return this._print;
            }
            set
            {
                this._print = value;
            }
        }
        public Computer()
        {
        }
        public Computer(IPrinter print)
        {
            this.Print = print;
        }
        public void ReceiveData()
        {
            this._print.Receive();
        }
        public void PrintData()
        {
            this._print.Print();
        }
    }
 }
}
4.測試一下打印機是否能正常工作:
namespace _1.InterfaceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Computer computer = new Computer();
            IPrinter printerA = new PrinterA();
            IPrinter printerB = new PrinterB();
            Console.WriteLine("I connected  PrinterA into computer and print something");
            computer.Print = printerA;
            computer.ReceiveData();
            computer.PrintData();
            Console.WriteLine("-------------------------------------------------------------“);
            Console.WriteLine("Now,PrinterA has some problem!I connected  PrinterB into computer and print something");
            computer.Print = printerB;
            computer.ReceiveData();
            computer.PrintData();
     
        }
    }
}
輸出結果:
測試成功!
此時又有另外一個問題,公司又重新購置了一臺不同類型的打印機,那又該如何實現呢?過程簡單。代碼如下:
namespace _1.InterfaceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Computer computer = new Computer();
            IPrinter newPrinter = new NewPrinter();
            Console.WriteLine("I connected  newPrinter into computer and print something");
            computer.Print = newPrinter;
            computer.ReceiveData();
            computer.PrintData();
            Console.ReadLine();
     
        }
    }
}
運行截圖:
哈哈,是不是很神奇,Computer一點都不用改動,就可以使新的設備正常運行。這就是所謂“對擴展開放,對修改關閉”。 

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()