介面與抽象

  • 2257
  • 0
  • C#
  • 2009-04-03

我記得在前一家公司有一天跟同事說到

介面跟抽象是什麼?

我回答介面定義了方法

只要某類別實作了該介面的話那麼此類別必須實作該介面的所有方法

在物件導向的設計中比較偏向是一種約束,我不管你怎麼做,但是你一定要會做

我引用書中的定義實做我設計的介面的物件必須要提供某個方法來讓外界呼叫

我記得在前一家公司有一天跟同事說到

介面跟抽象是什麼?

我回答介面定義了方法

只要某類別實作了該介面的話那麼此類別必須實作該介面的所有方法

在物件導向的設計中比較偏向是一種約束,我不管你怎麼做,但是你一定要會做

我引用書中的定義實做我設計的介面的物件必須要提供某個方法來讓外界呼叫

今天以設計面來說

好比.NET裡List有名為Sort這個多載的method

我這邊改用List.Sort 方法 (泛型 IComparer)這個例子

而我拿上次寫的用List.Sort(泛型 Comparison) 處理string混合integer的排序問題文章來改就好了

我新增了一個類別實做IComparer這個介面


class SortStringAndInteger : IComparer<string> {

    #region IComparer<string> 成員

    public int Compare(string x, string y) {
        int o, p;
        int.TryParse(x.Substring(1, x.Length - 1), out o);
        int.TryParse(y.Substring(1, y.Length - 1), out p);
        return -o.CompareTo(p);
    }
    #endregion
}

然後將排序的code改為


_temp.Sort(new SortStringAndInteger());

這樣是可行的,為什麼傳入的參數物件必須實做IComparer這個介面?

是因為_temp.Sort會去呼叫這個被instance的SortStringAndInteger這物件的Compare這個method來做排序的動作

這點有興趣的人可以用Reflector去追他的code

如果今天傳入的物件沒有實作IComparer這個介面就代表了,傳入的物件不一定擁有Compare這個method可以呼叫

那麼在coding的時候就會是一大困擾了,因為coding的工程師沒辦法知道該不該呼叫被傳入的物件的Compare這個方法

雖然也可以利用IS判斷式來確認...


if(SortStringAndInteger is IComparable)...

如果今天傳入的物件沒有這方法怎麼辦,那是不是又有Exception產生了

另外其他例子也可以參考策略模式的運作方式

還有介面能解決多重繼承的問題

programmer使用介面賦予一個類別擁有多種責任

 

那抽象呢?

以我的方式區分的話就是不能直接被instance的類別應該設計成抽象

所以cloudio覺得抽象相對於介面來說它的本質是很像物件的

雖然介面讓設計很靈活,實做介面的物件自己去決定怎麼做某件事就好了

但是有時候怎麼做某件事的那件事其實是一定要怎麼做的(聽起來有點饒口)

說穿了就是設計一個superclass,method等等的陳述式都寫好了

其他物件只要繼承他直接拿superclass的mthod來用就好了,當然繼承該superclass的物件本身也有其他的方法要做

但是宣告成abstract的method就像interface裡的method一樣了

不能宣告method主體,且inherit的class一定要實做該method

 

 不能被instance的類別應該設計成抽象這句話聽起來有點莫名其妙

不能不直接instance ? 那我要你幹嗎 ?

反向思考可以知道當我們希望為一群物件寫superclass

而這群物件在處理事情(do some method)的做法很不相同被當作superclass的abstract希望所有inherit的物件都自己去處理就好

且各自都需要在Constructor中設定各自內部的property時就很有用了

好比我將car這個superclass設計成abstract


abstract class Car {
    private Engine _engine;
    Car() {
        //設定此車輛引擎的參數
    }
    public void Operate() {
        //check 油量
        FillOil();
        TurnOnEngine();
    }
    public abstract void FillOil() {

    }
    public abstract void TurnOnEngine() {
        //依照引擎的參數做啟動引擎後車輛的設定
    }
}

每種車要加的油不一樣,且引擎運作的方式也不同

但是運轉的方式卻一樣,還有引擎是另外一個類別

每台車的引擎參數會不一樣,需要個別設定在Constructor中設定所以我沒辦法在superclass的Constructor中做設定

如果沒有設定的話用戶端呼叫TurnOnEngine這個method勢必會讓程式掛點

所以這時將car設定為abstractr就是很好的選擇

 

而介面與抽象都是不可以instance的但是可以reference

註:abstract提到的Constructor要傳入參數設定property一般的情況為

避免該class被instance後invoke的method會調用到property沒有設定就被拿來計算或處理等等。

 

初次寫此類文章,有觀唸錯誤煩請指點

感謝您

 

型別設計方針

抽象類別相對於介面的建議

Design Pattern: Strategy 模式