一、面向過程 我們是怎么思考和解決上面的問題的呢? 答案是:我們自己的思維一直按照步驟來處理這個問題,這是我們常規(guī)思維,這就是所謂的面向過程POP編程
面向過程想的思想步驟越多,變化越多,是無法掌控的,所以有時候非常復(fù)雜,就比如我們拿起來手機(jī)玩游戲如果按照POP編程則代碼如下: namespace OOP { /// <summary> /// OOP 面向?qū)ο缶幊?Object Oriented Programming /// </summary> class Program { static void Main(string[] args) { Console.WriteLine("我要玩手機(jī)游戲了"); Console.WriteLine("手機(jī)開機(jī)"); Console.WriteLine("打開游戲"); Console.WriteLine("正在打游戲"); Console.WriteLine("游戲結(jié)束"); } } } 但是出現(xiàn)不同手機(jī),不同的玩法,不同的游戲,那么又要重新寫類似的東西,所以面向過程雖然更更符合人的思考方式,但是及其不方便擴(kuò)展管理,不能夠重復(fù)使用,尤其是項目復(fù)雜的情況下,會使編程不好維護(hù) 但是怎么從POP轉(zhuǎn)換為OOP呢? 我們通過手機(jī)玩游戲,可以轉(zhuǎn)換一下思想,我們把對象進(jìn)行分析,可以把手機(jī),玩家,游戲分別定義為一個對象,可以參考如下: 1.玩家類 ![]() /// <summary> /// 玩家類 /// </summary> public class Player { /// <summary> /// 玩家Id /// </summary> public int Id { get; set; } /// <summary> /// 玩家名字 /// </summary> public string Name { get; set; } /// <summary> /// 玩手機(jī)方法 /// </summary> /// <param name="phone"></param> public void PayerPhone(Phone phone) { //玩手機(jī)需要先開機(jī) phone.Open(); //玩手機(jī)游戲 phone.PlayGame(); } } 2.手機(jī)類 ![]() /// <summary> /// 手機(jī)類 /// </summary> public class Phone { /// <summary> /// 手機(jī)Id /// </summary> public int Id { set; get; } /// <summary> /// 手機(jī)Name /// </summary> public string Name { set; get; } public void PlayGame() { Game game = new Game(); game.Start(); game.Paly(); game.Over(); } /// <summary> /// 手機(jī)開機(jī) /// </summary> public void Open() { Console.WriteLine($"{this.GetType().Name}手機(jī)開機(jī)"); } /// <summary> /// 手機(jī)關(guān)機(jī) /// </summary> public void Close() { Console.WriteLine($"{this.GetType().Name}手機(jī)關(guān)機(jī)"); } } 3.游戲類 ![]() /// <summary> /// 游戲類 /// </summary> public class Game { /// <summary> /// 開始 /// </summary> public void Start() { Console.WriteLine($"{this.GetType().Name}游戲開始"); } /// <summary> /// 正在進(jìn)行 /// </summary> public void Paly() { Console.WriteLine($"{this.GetType().Name}玩游戲"); } /// <summary> /// 結(jié)束 /// </summary> public void Over() { Console.WriteLine($"{this.GetType().Name}游戲結(jié)束"); } } 4.代碼調(diào)用 /// <summary> /// OOP 面向?qū)ο缶幊?Object Oriented Programming /// </summary> class Program { static void Main(string[] args) { //實(shí)例化一個玩家 Player player = new Player() { Id = 1, Name="小明" }; //小明想玩手機(jī),首先得需要一部手機(jī) Phone phone = new Phone() { Id = 1, Name = "努比亞" }; //小明開始玩手手機(jī) player.PayerPhone(phone); } } 我們按照對象劃分,就是所謂得萬物皆對象,然后我們把對象定義好封裝好,然后把對象屬性和動作都?xì)w結(jié)一起,這就所謂得畫格子,每個格子自成體系,內(nèi)部任意改動不會影響到別人,然后每個格子之間相互交互!雖然我們使思路更加復(fù)雜化,但是以后極其容易擴(kuò)展。
總的來說面向?qū)ο缶褪前岩郧鞍凑詹襟E考慮得然后劃為對象,然后對象之間交互組成宮嗯那個,功能與宮嗯那個之間組成系統(tǒng),系統(tǒng)與系統(tǒng)之間組成平臺,比如:一塊塊磚砌成墻,然后墻與墻之間組成房間,房間與房間之間組成一個大廈 三、面向?qū)ο蟮暮锰?,特點(diǎn)【封裝,繼承,多態(tài)】 1.封裝的好處 A:最主要的好處是:隔離,即是外部不用關(guān)系內(nèi)部怎么實(shí)現(xiàn),只要接口不變,內(nèi)部可以隨意擴(kuò)展 B:安全 private protect等數(shù)據(jù)結(jié)構(gòu),只能通過公開方法來訪問,而不能隨意修改致于保證數(shù)據(jù)的安全 C:降低耦合,提高重要性,經(jīng)理隱藏更多的東西 2.繼承的好處:就是為了代碼重用,通過繼承然后子類擁有父類的一切屬性和行為,但只能單繼承;重載(參數(shù)不一致,跟返回沒有任何關(guān)系) 3.多態(tài):意味著有多重形式。在面向?qū)ο缶幊谭妒街校瑝櫶ネ憩F(xiàn)為“一個接口,多個功能”。 4.多態(tài)的表現(xiàn)分為以下幾種 A:多態(tài)性可以是靜態(tài)或者動態(tài)的,在靜態(tài)多態(tài)中,函數(shù)響應(yīng)是在編譯時發(fā)生。在動態(tài)多態(tài)中,函數(shù)的響應(yīng)是在運(yùn)行時發(fā)生的。 B:接口多態(tài) C:繼承多態(tài) 下面的代碼能夠體現(xiàn)出來封裝、繼承、多態(tài) /// <summary> /// 父類 /// </summary> public abstract class ParentClass { public ParentClass() { Console.WriteLine($"(ParentClass)無參構(gòu)造函數(shù)"); } public void CommonMethod() { Console.WriteLine($"(ParentClass)父類普通方法"); } public virtual void VirturalMethod() { Console.WriteLine($"(ParentClass)父類VirturalMethod()"); } public virtual void VirturalMethod(int id) { Console.WriteLine($"(ParentClass)VirturalMethod(int id)"); } public abstract void AbstractMethod(); } //子類 public class ChildClass : ParentClass { /// <summary> /// 實(shí)例化子類的時候,是先完成父類的實(shí)例化 /// </summary> public ChildClass() { Console.WriteLine($"(ChildClass)無參構(gòu)造函數(shù)"); } /// <summary> /// new 隱藏基類方法,new 加不加一樣的效果 /// </summary> public new void CommonMethod() { Console.WriteLine($"(ChildClass)普通方法"); } public override void VirturalMethod() { Console.WriteLine($"(ChildClass)VirturalMethod"); //base.VirturalMethod(); //調(diào)用的父類的方法 } public sealed override void AbstractMethod() { Console.WriteLine("(ChildClass)子類抽象方法"); } } public class GrandClass : ChildClass { /// <summary> /// 可以重復(fù)覆寫,如果不喜歡被重寫,可以添加一個sealed /// </summary> //public override void AbstractMethod() //{ // throw new NotImplementedException(); //} public override void VirturalMethod() { base.VirturalMethod(); //調(diào)用的父類的方法 } public override void VirturalMethod(int i) { base.VirturalMethod(i); //調(diào)用的父類的方法 } } 然后再調(diào)用的時候會出現(xiàn)以下結(jié)果 static void Main(string[] args) { ParentClass parentClass = new ChildClass(); parentClass.CommonMethod(); //調(diào)用的父類的方法 普通方法由編譯時決定-能夠提高效率(由聲明時決定) parentClass.VirturalMethod(); //調(diào)用的子類方法 虛方法由運(yùn)行時決定的-多態(tài)靈活 (虛方法既可以覆寫,也可以不覆寫) parentClass.AbstractMethod(); //調(diào)用的子類的方法 ChildClass childClass = new GrandClass(); //VirturalMethod(int i) 里面有一句 base.VirturalMethod(int i) //為什么顯示 (ParentClass)VirturalMethod(int id) //原因是父類 ChildClass 沒有重寫ParentClass 的 VirturalMethod(int i)方法 childClass.VirturalMethod(1); Console.ReadLine(); } 四、說下抽象類和抽象接口的區(qū)別 1.抽象類和接口都不能直接被實(shí)例化。要是梨花,涉及到多態(tài)。抽象類要實(shí)例化,抽象類定義的變量必須指定一個子類變量,這個子類繼承并實(shí)現(xiàn)了抽象類的所有抽象方法。接口要實(shí)例化,接口定義的變量必須只想一個子類變量,這個子類變量繼承并實(shí)現(xiàn)接口的所有方法。 2.抽象要被子類繼承,接口要被子類實(shí)現(xiàn)。 3.接口里只能對方法進(jìn)行聲明,抽象里既可以對方法進(jìn)行聲明也,又可以實(shí)現(xiàn)。 4.抽象類里面的抽象方法被子類實(shí)現(xiàn),如果子類不能全部實(shí)現(xiàn),子類必須也是抽象類。接口里面的方法必須被子類實(shí)現(xiàn),如果子類不能全部實(shí)現(xiàn),子類必須是抽象類 5.接口里面的方法不能具體的實(shí)現(xiàn),這說明接口是設(shè)計的結(jié)果,而抽象類是重構(gòu)的結(jié)果。 6.抽象類里面可以沒有抽象方法,如果一個類里面有抽象方法,那么這個類一定是抽象類。 7.抽象類中的抽象方法都要被實(shí)現(xiàn),所以抽象方法不能是靜態(tài)的static,也不能是私有的private。 8.接口可以繼承接口,甚至可以擊沉多個接口;類可以實(shí)現(xiàn)多個接口,只能繼承一個類。 9.抽象類主要用來抽象類別,接口主要用來抽象方法功能。關(guān)注事務(wù)的本質(zhì),用抽象類;關(guān)注一種操作,用接口 接口可以定義一下內(nèi)容 /// <summary> /// 接口一般以大寫I開頭 /// </summary> public interface IExtend { /// <summary> /// 屬性可以,字段不行 /// </summary> int Tag { set; get; } /// <summary> /// 方法 /// </summary> void Play(); //string Remark = null; //不能聲明 //class Test { } //不能聲明 //Delegate void NoAction(); //不能聲明 /// <summary> /// 索引器 /// </summary> /// <param name="i"></param> /// <returns></returns> int this[int i] { get; } /// <summary> /// 事件 /// </summary> event Action DoNothindHandler; } 五、如何選擇抽象類和接口的區(qū)別 1:抽象類必須是一個父類,然后再方法不同的時候使用抽象實(shí)現(xiàn),主要是為了代碼重用 is a,所以抽象類可以說成是父類+約束,而且是單繼承 所以如果需要約束,一般選擇接口,因為接口可以多實(shí)現(xiàn)并且多繼承,除非項目中有代碼需要重用,這樣可以選擇抽象類 但是目前的大部分項目會選擇基類和接口聯(lián)合使用,比如有通用的屬性等使用基類來創(chuàng)建,如果需要約束功能的話一般使用接口來約束,所以接口和抽象類可以相輔相成! |
|