Level1_物件的繼承與封裝

物件的繼承、介面這些知識就像線上遊戲剛創建帳號時,系統會自動帶著玩家完成一些事項和基礎技能點擊。換句話說,繼承、介面對於Coding Online的玩家是很基本、重要的。當然,物件的封裝、多型也是相當重要,但不在此討論,各位玩家務必要好好學習。

物件的繼承、介面這些知識就像線上遊戲剛創建帳號時,系統會自動帶著玩家完成一些事項和基礎技能點擊。換句話說,繼承、介面對於Coding Online的玩家是很基本、重要的。當然,物件的封裝、多型也是相當重要,但不在此討論,各位玩家務必要好好學習。

在談繼承、介面之前,先來看看最基本的物件與類別之間的關係,物件與類別的差異在哪,這應該有很多在新手村的玩家都沒有辦法回答。甚至,已經出了新手出的玩家也沒有辦法好好地回答。簡單的來說,

類別是物件的藍圖,也就是將要描述的事物抽象化的結果,物件是根據類別被創建出來的

應該很多人看了還不懂差別在哪。舉個大師最常舉的例子,物件就好比房子而類別就是房子的設計圖。房子是根據設計圖建照出來的,設計圖上也會定義了許多房子的相關資訊,像是房子的大小、格局等等。再舉個例子,LEGO(樂高)的說明書與組合好的LEGO完成品,說明書就像是類別,在說明書裡會定義有哪些材料及個數。完成品就是照著說明書產出來的物件。

物件的繼承,可以讓子類別(繼承自的另一個類別的類別)擁有父類別(被繼承的類別)的屬性及方法。當然,子類別也可以重新定義父類別的屬性與方法。來看一個簡單的例子,一間公司裡面會有CEO、秘書、企劃人員、行銷人員..... 等等不同的職位。每種職位都會有一些特有資訊,所以可以將每種職位特有的資訊設計成一個類別,這裡以CEO與秘書來做範例。

/// <summary>
/// 秘書
/// </summary>
public class Secretary : Employee
{
    public DateTime WrokingHours { get; set; }
    /// <summary>
    ///  職務加給
    /// </summary>
    public int Allowance { get; set; }
}

/// <summary>
/// 執行長
/// </summary>
public class CEO : Employee
{
    /// <summary>
    /// 秘書
    /// </summary>
    public List<Secretary> Secretaries { get; set; }
}

然而,不管是CEO或秘書都是公司的員工。所以,需要一個員工的類別,把不同職位的共通屬性放在這一個類別,再將職位類別繼承員工類別。如此一來,職位類別就能專注的存放該職位特定的屬性,將共通的屬性像是員工代碼、分機等資訊放到基底類別上。

/// <summary>
/// 員工
/// </summary>
public class Employee : Person
{
    public string ID { get; set; }
    public string Ext { get; set; }
}

再者,每一個員工都是人,所以會有一些姓名、性別等等的共通資訊。所以,員工又繼承了人這一個類別,將個人的資訊放置到基底類別中。

/// <summary>
/// 人
/// </summary>
public class Person
{
    public string Name { get; set; }

    public string Gender { get; set; }

    public string Weight { get; set; }

    public string Height { get; set; }
}

上述的例子中,職位繼承了員工,員工又繼承了人。所以在物件的世界裡,我們可以從職位物件取得員工代碼或是這一位員工的性別,皆是透過繼承關係而來。

上述的例子,是為了讓大家了解繼承鏈的關係,所以會有多階層的繼承。在實務上,較不建議使用這樣的設計方式,請盡量使用聚合取代繼承。

介面

再談介面之前,先來講講另一件事。如果不是剛創建Coding online的玩家,應該會常常聽到「要依賴抽象類別,不要依賴具象類別」,如果這句話比喻成裝備,對於得到這個裝備的新手村玩家,打開背包的時候這一個裝備絕對是灰色的。因為物件導向的技能還沒點滿,所以這一句話跟天書一樣。

來試試用上述的例子來解釋這句話,我們都知道一間公司通常都會配一個以上的秘書給CEO,幫忙CEO管理日常行程,所以秘書一定要有管理CEO行事曆的能力。如果有訪談邀約或是公司會議直接詢問CEO是否有時間時,CEO通常會請對方轉洽秘書,讓祕書來管理。所以對於CEO而言,有邀約就是請秘書來管理,然後每天秘書在跟自己報告當天的行程即可。就算是秘書換人,CEO也不用管是誰,反正就是請對方找秘書就可以了。這個例子中,秘書就是一個抽象的代表,而真正在做秘書工作的人就是具象類別。CEO不用管每天的秘書是誰,有可能昨天的秘書是Ada,今天是Anna,明天是Christina,只要有需要就是請秘書來處理,反正不管是Ada, Anna還是Christina她們都是秘書,都會有管理行程的能力。

根據上面的敘述來更新程式碼,CEO的類別中,從依賴具象的秘書類別,變成秘書介面。原本的秘書類別也實作了秘書介面所需要的功能。

/// <summary>
/// 執行長
/// </summary>
public class CEO : Employee
{
    /// <summary>
    /// 秘書群
    /// </summary>
    public List<ISecretary> Secretaries { get; set; }
}

/// <summary>
/// 秘書介面
/// </summary>
public interface ISecretary
{
    DateTime WorkingHours { get; set; }

    /// <summary>
    ///  職務加給
    /// </summary>
    int Allowance { get; set; }

    /// <summary>
    /// 登記會議
    /// </summary>
    void BookingMetting(Event meeting);
}

/// <summary>
/// 秘書
/// </summary>
public class Secretary : ISecretary, Employee
{
    /// <summary>
    ///  上班時間
    /// </summary>
    public DateTime WrokingHours { get; set; }

    /// <summary>
    ///  職務加給
    /// </summary>
    public int Allowance { get; set; }

    /// <summary>
    /// 登記會議.
    /// </summary>
    /// <param name="meeting">會議資訊</param>
    public bool BookingMetting(Event meeting)
    {
        //// do something
    }
}

這個例子中,我們讓祕書類別實作秘書介面。然而,一個類別是可以實作多個介面,秘書類別除了實作秘書介面也可以再實作其他介面。舉個例子來說,新增一個女朋友的類別,此類別也實作女朋友介面,提供一些方法。接著,可以讓女朋友類別也實作秘書介面,這樣女朋友類別也就可以當成秘書來使用了。換句話說,這樣概念就是讓女朋友來當自己的秘書。

public class GirlFriend : IGirlFriend, ISecretary
{
    /// <summary>
    ///  職務加給
    /// </summary>
    public int Allowance { get; set; }

    /// <summary>
    /// 工作時間
    /// </summary>
    public DateTime WorkingHours { get; set; } 

    /// <summary>
    /// 暗黑技能A
    /// </summary>
    public void BlackFunctionA() { }

    /// <summary>
    /// 暗黑技能B
    /// </summary>
    public void BlackFunctionB() { }

    /// <summary>
    ///  登記時間
    /// </summary>
    public bool BookingMetting(Person person, Event meeting)
    {
        //// do something
        return true;
    }
}

當然可以讓祕書類別實作女朋友介面,如此一來,秘書也就有女朋友的暗黑技能了(筆者心聲: 當CEO真好.......)。不過,秘書實作女朋友介面與女朋友實作秘書介面,雖然在使用上是一模一樣的。但是,在實際上的意義可以相差許多。

/// <summary>
/// 秘書
/// </summary>
public class Secretary : Employee, ISecretary, IGirlFriend
{
    public DateTime WrokingHours { get; set; }
    /// <summary>
    ///  職務加給
    /// </summary>
    public int Allowance { get; set; }

    /// <summary>
    /// 工作時間
    /// </summary>
    public DateTime WorkingHours { get; set; }

    private Calendar _bossCalendar;

    public bool BookingMetting(Person person, Event meeting)
    {
        throw new NotImplementedException();
    }

    public void BlackFunctionA()
    {
        //// do something
    }

    public void BlackFunctionB()
    {
        //// do something
    }
}

當有人想要跟CEO約時間開會時,只需要跟其中一位秘書booking時間即可

    var jack = new CEO();
    var isBooking = jack.Secretaries.First().BookingMetting(
            new Person()
            {
                Name = "Andy"
            }, 
            new Event()
            {
                Date =  new DateTime(2015, 12, 25)
            }
        );

透過以上的例子,希望能夠讓大家了解「要依賴抽象類別,不要依賴具象類別」的原理,介面就是這一句話中抽象類別之一。當物件要使用另一個物件的功能時,盡可能的使用介面,而不適直接使用該物件。

在現實生活中還有許多這樣的案例,像是大家每天都在使用的USB,只要符合USB接頭的規格,不管你是什麼廠牌都是可以使用的。

免責聲明:

"文章一定有好壞,文章內容有對有錯,使用前應詳閱公開說明書"