iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
自我挑戰組

30天開啟.NET後端工程師的旅程系列 第 11

Day 11 物件導向 OOP

  • 分享至 

  • xImage
  •  

前言

Day 9跟Day 10兩天分別說明了類別跟函式。

開始要講到重要的抽象概念(還是初學者的我遇到的,面試筆試的考題有蠻多都是從這裏的概念出來的)

物件導向(Object Oriented Programming)概念

對當時剛開始接觸到這個概念的我來說,有夠抽象,似懂非懂,當要求我詳細的描述,又似乎無法很好的解釋與說明。

首先提到物件,在網路上可以找到像下面這樣的相關定義。

在計算機科學中,物件是一個記憶體位址,其中擁有值,這個位址可能有標識符指向此處。物件可以是一個變數,一個資料結構,或是一個函式。是物件導向中的術語,既表示客觀世界問題空間中的某個具體的事物,又表示軟體系統解空間中的基本元素。

(恩...如果是身為初學者的我,看完上面的定義絕對是…滿頭問號啊!!!!!!)

就從類別跟物件的差異開始解釋起吧:

  1. 類別(Class): 類別是一種程式碼結構,它充當了物件的模板或藍圖。它定義了一個物件應該有哪些屬性(稱為成員變數)和可以執行的操作(稱為方法)。一個類別通常包括了物件的結構和行為描述,但它本身並不是物件的實例。類別的定義包括了資料成員的聲明以及方法的實現,這些方法可以用來操作該類別的物件實例。
  2. 物件(Object): 物件是根據類別的定義所創建的實例。它是具體的、存在於記憶體中的實體,包含了該類別所描述的屬性的實際值和可以執行的方法。物件通常是動態生成的,它們是我們在程式中使用的主要實體,用來處理不同的資料和操作。

物件導向程式設計的主要目標是提高程式碼的可維護性、可擴展性和可重用性。它通常將複雜的系統分解為多個小型、可管理的物件,並且強調模組化和抽象化的設計方式。
這種方法有助於更好地理解和維護程式碼,並促進團隊協作。因此,物件導向概念在軟體開發中廣泛應用並被視為一種強大的編程範式。

那物件導向呢基本上就是把程式內的東西都變成以物件的方式呈現。
在這個程式中,物件與物件之間互相區別,但又藉由程式碼互相呼應。

簡單來說,類別是一個設計圖,它定義了物件應該長什麼樣子以及可以做什麼事情。
當我們需要一個具體的實例來處理特定任務時,我們創建一個物件,並基於該類別的定義來設定其屬性和執行相關的操作。

類別和物件之間的關係可以比喻為建造圖紙(類別)和實際建築物(物件)之間的關係。
圖紙告訴您如何建造房子,但實際的房子是根據這些圖紙所建造的。
同樣地,類別告訴電腦如何建立物件,而物件是根據這些類別的定義所建立的實例,用於執行特定的任務。

請問「類別」可不可以包含「物件」?

在物件導向程式設計中,一個類別(Class)是用來定義物件(Object)的模板或藍圖,沒有實體概念。

換句話說

類別描述了一個物件的結構、屬性和方法。物件則是根據這個類別的定義實際創建的實例。
所以,類別本身並不包含物件,它只是定義了物件應該具備的特性和行為。
當您創建一個物件時,您實際上是根據該類別的定義創建了一個物件的實例。這個實例是該類別的一個具體示例,包含了該類別定義的資料和方法。

總結來說,類別定義了物件的結構,但不包含物件本身。物件是根據類別的定義創建的實例。您可以根據同一個類別的定義創建多個不同的物件實例。

物件導向三大特性(封裝、繼承、多型)

繼承(Inheritance)

在物件導向程式設計中,繼承是一個重要的概念,它允許我們建立一個新的類別(子類別)基於現有類別(父類別)的屬性和方法。以下是一些關於繼承的重要觀念:

  1. 單一父類別:一個子類別只能有一個父類別,這種概念稱為單一繼承。換句話說,每個類別只能直接繼承自一個父類別。
  2. 父子關係:對於子類別(例如Employee),父類別(例如Person)是其繼承來源,稱為父類別或超類別(super class)。子類別繼承了父類別的屬性和方法。
  3. 預設父類別:如果在類別的定義中沒有明確指定父類別,則該類別將自動繼承自一個名為**object**的預設父類別。
  4. 建構函數:當建立子類別的實例時,同時也會建立父類別的實例。子類別可以擁有自己的建構函數,但通常也會呼叫父類別的建構函數。

可以再舉一些其他的例子來說明繼承的概念:
1. 動物與具體動物
考慮一個簡單的動物層次結構。有一個基本的 Animal 類別,然後裡面有一些具體的動物類別,例如 DogCatDogCatAnimal 的子類別。

public class Animal
{
    public string Species { get; set; }
    public void MakeSound() { }
}

public class Dog : Animal
{
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public bool IsLazy { get; set; }
}

在這個例子中,DogCat 繼承了 Animal 的屬性和方法。
例如,它們都有 Species 屬性,而且都可以執行 MakeSound 方法。
同時,Dog 有自己的 Breed 屬性,而 CatIsLazy 屬性。

2. 形狀與具體形狀
考慮一個簡單的圖形層次結構。有一個基本的 Shape 類別,然後有一些具體的形狀類別,例如 CircleRectangle

public class Shape
{
    public double Area { get; set; }
    public void Draw() { }
}

public class Circle : Shape
{
    public double Radius { get; set; }
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
}

在這個例子中,CircleRectangle 繼承了 Shape 的屬性和方法。
例如,它們都有 Area 屬性,而且都可以執行 Draw 方法。
同時,Circle 有自己的 Radius 屬性,而 RectangleWidthHeight 屬性。

多用合成,少用繼承
在設計軟體時,通常建議多用合成(Composition)而少用繼承。
合成是一種將現有類別的物件組合到新類別中的方式,而不是繼承其屬性和方法。這種方法更靈活,減少了類別之間的耦合性,並提高了程式碼的可維護性。

封裝(Encapsulation)

封裝是一種程式設計原則,它指的是將一個物件的狀態(屬性)和行為(方法)捆綁在一起,並將其隱藏在物件內部,只向外部提供有限的訪問接口。
封裝允許我們將物件的實現細節隱藏起來,只公開對外界有意義的操作。

封裝就像是你的銀行帳戶。

你有一個銀行帳戶,希望保護它的安全,不希望任何人都能夠輕易地進行資金操作。所以,銀行為你的帳戶提供了一個安全的密碼和存取卡。這個密碼和存取卡就像是你的帳戶封裝,只有你知道密碼並持有存取卡的人才能夠進行帳戶操作。

其他人,包括你的家人或朋友,不能直接訪問或管理你的銀行帳戶。他們必須經過授權的方式,例如提供密碼或存取卡,才能夠進行相關的交易。這就是一個封裝的概念,它將你的財務信息保護在安全的封裝內,只有授權的人才能夠訪問和操作。

在程式設計中,封裝也是類似的概念。你可以將數據和方法封裝在一個類別中,只有該類別的方法才能夠訪問它們。這樣可以確保數據的安全性和方法的可控性,同時隱藏了實現細節,使程式碼更加模組化和易於維護。

封裝的優點包括:

  • 隱藏實現細節:外部使用者不需要知道物件內部的具體實現細節,這有助於降低複雜性並提高代碼的可維護性。
  • 保護數據完整性:通過將屬性設為私有,我們可以確保數據只能通過特定的方法進行訪問和修改,從而減少了錯誤的可能性。
  • 提供訪問控制:我們可以通過設置不同的訪問修飾符(例如**publicprivateprotected**)來控制哪些部分的物件可以被外部訪問,這有助於實現良好的封裝。

以下是一個簡單的 C# 類別示例,演示了封裝的概念:

public class Person
{
    private string name;  // 私有欄位,只能在類內部訪問

    public Person(string name)
    {
        this.name = name;
    }

    // 公開的方法用於訪問 name 屬性
    public string GetName()
    {
        return name;
    }

    // 公開的方法用於修改 name 屬性
    public void SetName(string newName)
    {
        name = newName;
    }
}

在上面的例子可以看到, name 的欄位設置為private的,只能在 Person 類別的內部訪問。然後,再寫兩個公開的方法 GetNameSetName,用於查找和修改 name 屬性。這樣,外部使用者只能通過這些方法來與 name 互動,而不需要知道 name 的具體實現細節。

多型(Polymorphism)

多型是一種物件導向程式設計的特性,它允許不同的類別共享相同的介面或基類,但具有不同的實現。多型的核心概念是:相同的方法名稱可以在不同的類別中有不同的實現,並且可以在運行時選擇適當的實現。

多型的優點包括:

  • 代碼重用:多型允許多個類別共享相同的介面或基類,這意味著可以重用已經存在的代碼。
  • 擴展性:可以輕鬆地添加新的類別,並使其符合相同的介面或基類,以擴展應用程序的功能。
  • 彈性:多型使代碼更加靈活,可以根據不同的情境選擇適當的實現。

在 C# 中,多型通常通過繼承和介面實現。以下是一個簡單的示例,演示了多型的概念:

public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("Some generic animal sound");
    }
}

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Bark! Bark!");
    }
}

public class Cat : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Meow!");
    }
}

在上面的程式碼中,Animal 類別中的 MakeSound 方法被標記為 virtual
這表示它是一個可以被子類別覆寫(override)的方法,當一個方法被標記為 virtual 時,它可以在子類別中重新實作(override),以提供不同的行為。

接下來的 Dog 類別和 Cat 類別都繼承自 Animal 類別,並使用 override 關鍵字來覆寫 MakeSound 方法。這意味著它們提供了自己獨特的 MakeSound 實作,不同於 Animal 類別中的預設實作。

當你建立 DogCat 的實例並呼叫 MakeSound 時,它們會執行各自的覆寫實作,而不是 Animal 中的預設實作。這就是多型(polymorphism)的一個示例,其中不同的物件實例可以對相同的方法呼叫產生不同的行為。

像我們在Day 9 提到的多載(Overloading)就是多型的其中一種實現方式喔


第11天挑戰完成!!!


上一篇
Day 10 深入了解C#函數(Functions)的原理和用法
下一篇
Day 12 單一職責原則 (Single Responsibility Principle)
系列文
30天開啟.NET後端工程師的旅程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言