實(shí)例解讀面向?qū)ο蠛诵?,所有例子基?C#,涉及我們實(shí)務(wù)中最常關(guān)心的問(wèn)題:
1、封裝、繼承、多態(tài);
2、抽象類(lèi)、接口;
3、委托、事件。
每個(gè)對(duì)象都包含它能進(jìn)行操作的所有信息(不必依賴(lài)其他對(duì)象),這個(gè)特性稱(chēng)為封裝。
封裝降低了耦合,類(lèi)內(nèi)部的實(shí)現(xiàn)可以自由的修改,使類(lèi)具有清晰的對(duì)外接口。
對(duì)象的繼承代表了一種“一般到特殊”的關(guān)系,例如 學(xué)生(Student)是一種人類(lèi)(Person)。
繼承定義了類(lèi)如何相互關(guān)聯(lián),共享特性。
繼承的工作方式是,定義父類(lèi)和子類(lèi),或叫做基類(lèi)與派生類(lèi),上面的例子中,可以讓 Student(子類(lèi))繼承 Person(父類(lèi))。
多態(tài):表示不同的對(duì)象可以執(zhí)行相同的動(dòng)作,但要通過(guò)它們自己的實(shí)現(xiàn)代碼執(zhí)行。
這個(gè)文字理解比較抽象,具體說(shuō)明見(jiàn)下面示例中講解:
例子分為 父類(lèi),子類(lèi),調(diào)用 三部分。
先建立個(gè)MVC項(xiàng)目OOPDemo,我們定義一個(gè)父類(lèi):抽象的圖形類(lèi)(Shape), 子類(lèi) :矩形類(lèi) (Rectangle),在 HomeController 中 Index 方法中調(diào)用。
父類(lèi):
定義一個(gè)屬性Name 和方法 GetName, 將該成員聲明為虛擬的(virtual, 有方法體),除了字段不能是虛擬的,屬性、事件和索引器都可以是虛擬的,通常虛擬的是方法, 子類(lèi)通過(guò) override來(lái)覆寫(xiě)。
public class Shape { public string Name { get; set; } public Shape(string name) { this.Name = name; } public virtual string GetName() { return "父類(lèi)的圖形名: "+ Name; } }
子類(lèi)繼承父類(lèi):
public class Rectangle:Shape { public Rectangle(string name):base(name) { } public override string GetName() { return "子類(lèi)的圖形名: " + Name; } public double Length { get; set; } public double Width { get; set; } public double GetArea() { double area = Length * Width; return area; } }
子類(lèi)中關(guān)于繼承的說(shuō)明:
1、子類(lèi)擁有父類(lèi)非private的屬性和功能
子類(lèi)擁有父類(lèi)的 屬性Name,GetName()方法。
* 構(gòu)造方法有一些特殊,它不能被繼承,只能被調(diào)用(使用 base)。
public Rectangle(string name):base(name)
{ }
2、子類(lèi)具有自己的屬性和功能,即子類(lèi)可以擴(kuò)展父類(lèi)沒(méi)有的屬性和功能。
矩形有自己的 長(zhǎng)、寬屬性,及計(jì)算面積的 GetArea 方法。
public double Length { get; set; } public double Width { get; set; } public double GetArea() { double area = Length * Width; return area; }
3、子類(lèi)可以以自己的方式實(shí)現(xiàn)父類(lèi)的功能(方法重寫(xiě))
通過(guò)override重寫(xiě)
public override string GetName() { return "子類(lèi)的圖形名: " + Name; }
調(diào)用
在HomeController的Index方法中獲取名字。
public IActionResult Index() { Shape rec1 = new Rectangle("正方形"); ViewBag.Name = rec1.GetName(); return View(); }
前端通過(guò)ViewBag獲取Name
調(diào)用時(shí)關(guān)于多態(tài)的說(shuō)明
1、子類(lèi)以父類(lèi)身份出現(xiàn)
注意是以 Shape(父類(lèi)) 而不是 Rectangle(子類(lèi)) 來(lái)聲明的,然后用 Rectangle(子類(lèi))來(lái)實(shí)例化。(對(duì)象的聲明是父類(lèi),而不是子類(lèi),實(shí)例化的對(duì)象是子類(lèi))
Shape rec1 = new Rectangle("正方形");
2、子類(lèi)在工作時(shí)以自己的方式來(lái)實(shí)現(xiàn)(覆寫(xiě)父類(lèi)方法)
public override string GetName() { return "子類(lèi)的圖形名: " + Name; }
當(dāng)方法被調(diào)用時(shí),都只有位于對(duì)象繼承鏈最末端的方法會(huì)被調(diào)用。也就是說(shuō),虛方法是按照運(yùn)行時(shí)類(lèi)型而非編譯時(shí)類(lèi)型進(jìn)行動(dòng)態(tài)綁定調(diào)用的。
3、子類(lèi)以父類(lèi)身份出現(xiàn)時(shí),子類(lèi)特有的屬性和方法不可使用
這些都是不能用的:
public double Length { get; set; } public double Width { get; set; } public double GetArea() { double area = Length * Width; return area; }
例如 rec1.GetArea() ,這個(gè)是獲取不到的。
抽象類(lèi)
回顧下我們的例子。
Shape實(shí)際上不會(huì)實(shí)例化,它只是抽象出一些共同的東西用來(lái)繼承。
抽象類(lèi)通常代表一個(gè)抽象概念,它提供一個(gè)繼承的出發(fā)點(diǎn),當(dāng)設(shè)計(jì)一個(gè)新的抽象類(lèi)時(shí),一定是用來(lái)繼承的,所以,在一個(gè)以繼承關(guān)系形成的等級(jí)結(jié)構(gòu)里面,樹(shù)葉節(jié)點(diǎn)應(yīng)當(dāng)是具體類(lèi),而樹(shù)枝節(jié)點(diǎn)應(yīng)該是抽象類(lèi)。也就是說(shuō),具體類(lèi)不是用來(lái)繼承的。
考慮把沒(méi)有任何意義的父類(lèi)改成抽象類(lèi),讓抽象類(lèi)擁有盡可能多的共同代碼,擁有盡可能少的數(shù)據(jù)。
我們來(lái)修改一下例子。
將父類(lèi)做如下方框處更改,其他的都不變。
我們將Shape改成了抽象類(lèi), public abstract class Shape {…}
將GetName刪除了方法體,改成了抽象方法 public abstract string GetName();
說(shuō)明:
1、抽象類(lèi)不能實(shí)例化
2、抽象方法是必須被子類(lèi)重寫(xiě)的方法(可以看成是沒(méi)有實(shí)現(xiàn)體的虛方法)
3、如果類(lèi)中包含抽象方法,那么類(lèi)就必須被定義為抽象類(lèi),不論是否還包含其他一般方法。
接口
聲明接口的語(yǔ)法與聲明抽象類(lèi)完全相同,但不允許提供接口中任何成員的執(zhí)行方法。
實(shí)現(xiàn)接口的類(lèi)就必須實(shí)現(xiàn)接口中所有的方法和屬性。
我們來(lái)定義一個(gè)接口:
/// <summary> /// 定義各種各樣的面積算法 /// </summary> public interface ICal { string GetAreaAlgorithm(); }
在Rectangle中繼承這個(gè)接口,并實(shí)現(xiàn)接口的方法
public class Rectangle:Shape, ICal { // 此處省略其他代碼xx行... // 實(shí)現(xiàn)接口 ICal 中的方法 public string GetAreaAlgorithm() { return "矩形的面積算法:長(zhǎng) × 寬"; } }
修改調(diào)用方法:
public IActionResult Index() { Shape rec1 = new Rectangle("正方形"); ViewBag.Name = rec1.GetName(); ICal cal= new Rectangle("正方形2"); ViewBag.Cal = cal.GetAreaAlgorithm(); return View(); }
顯示結(jié)果:
1、類(lèi)是對(duì)對(duì)象的抽象;抽象類(lèi)是對(duì)類(lèi)的抽象;接口是對(duì)行為的抽象
2、如果行為跨越不同對(duì)象,可使用接口
3、從設(shè)計(jì)角度看,抽象類(lèi)是從子類(lèi)中發(fā)現(xiàn)公共的東西,泛化出父類(lèi),而接口根本不知道子類(lèi)的存在,方法如何實(shí)現(xiàn)還不確認(rèn),預(yù)先定義。
抽象類(lèi)往往都是通過(guò)重構(gòu)得來(lái)的,抽象類(lèi)是自底向上抽象出來(lái)的,而接口是自頂向下設(shè)計(jì)出來(lái)的。
祝學(xué)習(xí)進(jìn)步 :)
聯(lián)系客服