OOP 物件導向學習筆記
目錄
物件導向四大原則
封裝(Encapsulation)
封裝(Encapsulation)在物件導向程式設計中是用來將資料與函式的實作內容包裝、隱藏起來的技巧,其中資料更常被稱為類別的成員屬性(Attributes)、函式更常被稱為類別的成員方法(Methods)。
- 「封裝」有時被稱為物件導向程式設計的第一大支柱或原則。
- 類別或結構可以指定其每個成員在類別或結構外部程式碼的可存取程度。
- 無法從類別或元件外部使用的方法和變數可以隱藏,以限制編碼錯誤或惡意探索的可能性。
舉個例子,如同部落格發文,公開貼文大家都看的到,設定私人或草稿除了自己其他人都看不到。
說白了,就是公開出來的才看的到(public
)。而未公開的,就怎麼也找不到(private
、protected
)。
public
顧名思義, 任何人都可以存取
|
|
|
|
private
只有 class
本身可以存取
|
|
protected
自身Class及被繼承的 class
可以存取
|
|
C# 額外其他3種存取方式
internal
:- 類別: 相同命名空間 (相同dll存取) 可存取
- 成員: 只有自身
Class
可存取
protected internal
:- 類別: 自身
Class
, 被繼承Class
皆可存取 - 成員: 自身
Class
, 相同命名空間, 被繼承Class
皆可存取
- 類別: 自身
private protected
:- 類別: 自身
Class
, 被繼承Class
皆可存取 - 成員: 自身
Class
可存取, 被繼承Class
無法存取
- 類別: 自身
繼承(Inheritance)
- 類別 (而不是結構) 支援繼承的概念。
- 衍生自另一個類別的類別,稱為 基類,會自動包含基類的所有公用、受保護和內部成員,但建構函式和完成項除外。
- 類別可宣告為抽象,這表示其一或多個方法沒有任何實作。 (雖然抽象類別無法直接具現化,但是它們可以做為其他能提供遺失實作之類別的基底類別。)
- 類別也可以宣告為密封(
sealed
),以防止其他類別繼承它們。(類別可以藉由將本身或成員宣告為sealed
,以防止其他類別繼承自它或其任何成員)
關係是一層一層繼承下來的, 舉例來說,手機可以通話、傳訊息,所以各品牌都是繼承 手機 的功能 並延伸自己的特色及功能,比如說 早期 3310 有基本手機功能且黑白畫面, 而目前 Iphone 有彩色畫面且還能上網
|
|
|
|
多型(Polymorphism)
- 多型在希臘文中表示「多種形狀」
- 在執行階段,衍生類別物件可視為方法參數和集合或陣列等位置中的基底類別物件。 當這個多型發生時,物件的宣告型別與其執行時間型別不再相同。(比較文言文的說法😓)
- 就是同一件事情,有需多不同的做法(比較白話文的說法😛)
同一件事情,有需多不同的做法,舉個例子,如同 粽子,同是粽子有分南部粽、北部粽、東部粽、潮州粽…等不同做法。
-
interface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
// 介面多型 public class Program { static void Main(string[] args) { I粽子 南部粽做法 = new 南部粽(); 南部粽做法.做法();// Output: 南部粽:米半熟~水煮 I粽子 北部粽做法 = new 北部粽(); 北部粽做法.做法();// Output: 北部粽:油飯~蒸煮 北部粽做法.評價();// Error: I粽子 未包含 評價 的定義(也就是說, 子類以父類建立時,只能以父類有的為主) Console.ReadKey(); } public interface I粽子 { void 做法(); } public class 南部粽: I粽子{ public void 做法(){ Console.WriteLine("南部粽:米半熟~水煮"); } } public class 北部粽: I粽子{ public void 做法(){ Console.WriteLine("北部粽:油飯~蒸煮"); } public void 評價(){ Console.WriteLine("好吃"); } } }
-
virual
method1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
// virual method public class Program { static void Main(string[] args) { Coffee normalcafe = new Coffee(); ShallowPeas sp = new ShallowPeas(); DeepPeeledBeans dp = new DeepPeeledBeans(); Coffee[] cafes = { normalcafe, sp, dp }; foreach(var cafe in cafes){ cafe.make(); } Console.ReadKey(); // Output: // Brewed and taste normal // Brewed and tasted sour // Brewed and tasted bitter } public class Coffee { public virual void make(){ Console.WriteLine("Brewed and taste normal"); } } public class ShallowPeas: Coffee{ public override void make(){ Console.WriteLine("Brewed and tasted sour"); } } public class DeepPeeledBeans: Coffee{ public override void make(){ Console.WriteLine("Brewed and tasted bitter"); } } }
-
可以使用
base
取得父類方法或屬性1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
public class Program { static void Main(string[] args) { Coffee normalcafe = new Coffee(); Americano Acafe = new Americano(); normalcafe.make();// Output: Brewed and taste normal Acafe.make();// Output: Brewed and taste normal Console.ReadKey(); } public class Coffee { public virual void make(){ Console.WriteLine("Brewed and taste normal"); } } public class Americano: Coffee{ public override void make(){ base.make(); } } }
-
Use
New
to hide the base class member1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Use new to hide the base class member public class Program { static void Main(string[] args) { ShallowPeas sp = new ShallowPeas(); sp.make();// Output: Brewed and tasted sour Coffee normalcafe = (Coffee)sp; normalcafe.make();// Output: Brewed and taste normal Console.ReadKey(); } public class Coffee { public void make(){ Console.WriteLine("Brewed and taste normal"); } } public class ShallowPeas: Coffee{ public new void make(){ Console.WriteLine("Brewed and tasted sour"); } } }
抽象化(Abstraction)
-
以特性來說,就是將需求轉為類別,而此類別可以包含狀態(Property)及行為(Method),前幾個特性皆有示例已包含抽象化特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
public class Program { static void Main(string[] args) { Coffee cafe = new Coffee(); cafe.from = "Ethiopia"; cafe.type = "ShallowPeas" Console.WriteLine($"來自{cafe.from}的{cafe.type}咖啡"); cafe.make(); Console.ReadKey(); // Output: // 來自Ethiopia的ShallowPeas咖啡 // Brewed and tasted sour } public class Coffee { public string from { get; set; } public string type { get; set; } public void make(){ Console.WriteLine("Brewed and taste sour"); } } }
-
abstract
抽象類別- 不能被實例化
- 如不應該被實體化成一個物件,此類別就應該成為抽象類別
- 子類必須要
override
方法才能使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
public class Program { static void Main(string[] args) { var pg = new Lou(); Console.WriteLine($"The Programming Language is {pg.language}"); pg.Coding(); Console.ReadKey(); // Output: // The Programming Language is CSharp // 努力寫專案 } public class Programer { public string language { get; set; } public abstract void Coding(); } public class Lou: Programer{ public string language { get; set; } => "CSharp"; public override void Coding(){ Console.WriteLine("努力寫專案"); } } }
參考資料
- MSDN - C# 文件
- YaYi - OOP三大特性:封裝、繼承、多型
- 保持前進、持續優化程式碼內涵
- 數據交點文摘 - 物件導向程式設計四大支柱之一:封裝
- 理工宅 - c# Public? Private? protected? 比較各種修飾詞存取範圍
- 程式人生 - C#多型的實現:虛方法、抽象類、介面
- 搞笑談軟工 - 什麼是物件導向(3):Polymorphism
- 伊果的沒人看筆記本 - 菜雞與物件導向 (5): 多型
- 伊果的沒人看筆記本 - 菜雞與物件導向 (6): 抽象、覆寫
- 菜鳥工程師 肉豬 - Java 什麼是多載(Overload), 覆寫(Override), 多型(Polymorphism)