1. 程式人生 > >【C#】之 封裝、繼承與多型

【C#】之 封裝、繼承與多型

我們知道封裝、繼承和多型是面向物件方法設計中的三大基本特性,下面將具體講解這三個特性的具體表現及意義。

#一、封裝

##1、說明

  從字面意思上看,封裝就是打包的意思,將什麼包裝起來,專業一點就是資訊的隱藏,將物件的屬性和方法打包成一個相對獨立的單位,儘可能隱蔽物件的內部細節,對外形成一個邊界,若有其他類或方法想訪問這個被封裝了的類,需要通過介面來實現,即對外有函式作為通道,對內有變數作為原料。

  物件安全性的高低取決於其封裝的程度,我們在宣告屬性方法時,會有public、private、protected、internal等訪問修飾符,這些修飾符就定義了訪問的級別,從而也就決定了封裝的程度。

		public——公共成員,完全公開,沒有訪問限制
		private——私有成員,在類的額內部才可以訪問
		protected——保護成員,該類內部和繼承類(子類) 中可以訪問
		internal——當前程式集內可以訪問,類的預設訪問修飾符

##2、為什麼要封裝
  可以說,在任何程式中,我們無時無刻都在運用封裝這一特性,那麼我們為甚麼這麼頻繁的使用封裝呢?

  當物件被建立時,如果沒有被封裝,即可以通過物件的引用獲取任意成員的屬性值,並能夠給所有的成員屬性任意賦值。這樣是非常危險的,第一,物件中的成員屬性是物件本身的特有屬性,如果很輕易的被其他物件訪問並修改,那這些屬性存的意義就沒有了。第二

,物件中的成員方法只有部分是給外部提供的,有些是物件自己使用的方法,如果外部能夠隨意呼叫物件內部的所有方法,這個方法存在也就沒有意義了。

  舉個例子,在”人”的物件中,提供了”走路”的方法,而”走路”的方法又是通過在物件內部呼叫”邁左腿”和” 邁右腿”兩個方法組成。如果使用者在物件的外部直接呼叫” 邁左腿”或” 邁右腿”的方法就沒有意義,應該只讓使用者能呼叫”走路”的方法。

  有了封裝,我們就能夠有效的避免外部錯誤對內部造成的“交叉感染”,使軟體錯誤能夠區域性化。

封裝好處:

 1、良好的封裝能夠減少耦合。

2、類內部的結構可以自由修改。

3、可以對成員進行更精確的控制。

4、隱藏資訊,實現細節。

#二、繼承

##1、說明

  繼承是父與子的關係,當代碼中需要申請多個類或多個方法時,如果這些類或方法有一定相同的屬性,為了減少程式碼的冗餘,可以使用繼承關係,減少程式碼量。

  子類或子函式可以繼承父類或父函式中的所有屬性,父類中含有所有子類的共同特徵。在主函式中為子類或子方法賦值時,可以直接呼叫父類或父方法中的屬性。

##2、建構函式中的繼承
  之前我們有說過建構函式,他其實就是在一定程度上改變了封裝物件介面的型別,不僅減少了程式碼量,而且增加了被訪問物件的安全性。那麼如果兩個類或方法存在繼承關係,在其中使用建構函式時,我們需要注意哪些呢?

  由於子類中屬性可能比較多,需要利用到有參的建構函式,當子類在例項化時,會呼叫父類無參的建構函式來得以實現。但是類都可以例項化,父類也不例外,當父類也利用有參建構函式例項化時,就會覆蓋了原來的無參的建構函式(類中都會預設有一個無參的建構函式),從而導致子類的例項化無法實現,所以此時可以再在父類中建立一個無參的建構函式來供子類的呼叫。

  那麼如果子類中有參的建構函式與父類中有參的建構函式有相同的引數,能不能直接通過子類有參的建構函式呼叫父類有參的建構函式來減少程式碼的輸入量呢?答案是肯定的,這是就用到了base,在子類建構函式後面加上“:base(相同的引數型別)

這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

#三、多型

##1、說明

多型

通俗來講:就是物件能夠表現多個型別的能力。
比較全面的說法:就是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數倒底會指向哪個類的例項物件,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。我們不修改程式程式碼就可以改變程式執行時所繫結的具體程式碼,讓程式選擇多個執行狀態,這就是多型。

好吧,舉個例子:
  我們定義動物這個類,他有“顏色”屬性,有“叫”這個方法,但是如果將動物例項化,比如貓,狗,老鼠等,他們都各自有各自的顏色屬性值和叫的方法值。這些都需要在執行期間才能決定,這樣在執行期間讓程式選擇多個執行狀態,就是多型。

##2、實現形式
###1>介面
  介面是多型的體現形式,用 Interface 來定義,語法如下:

	 [訪問修飾符] interface 介面名
			{
				//介面成員定義
			}

說明:
介面不能直接例項化
介面中沒有方法體的實現
類似於抽象基類,繼承介面的任何非抽象型別都必須實現介面的所有成員
介面之間支援多重繼承,但是類不能,類只有一個父類

###2>重寫

  子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法。

  重寫時,子類的方法名和父類的方法名重名,但是子類方法名下會出現一條綠線(不影響使用)

解決綠線方法:
1、可以在子類方法的修飾符後面加new,隱藏父類方法(無論是否加new都不影響使用)
2、可以在父類的方法的修飾符後面加virtual(變成虛方法),在子類的方法的修飾符後面加override(使子類重寫父類方法,變成實的),在子類的方法中可以直接使用父類方法也可以重新賦值。

作用:
  如果我們執行一個操作:申請很多類,將這些類放到集合當中,遍歷這個集合的時候,把這些類中的方法全部調用出來。
  如果沒有重寫,我們就需要一個個判斷子類父類能不能轉換,然後一個個呼叫方法。如果有了重寫,我們只需要判斷子類父類能不能轉換,然後再最後呼叫一個方法就可以了,因為名字相同,只要一個方法呼叫就可以,內容可以重新覆蓋。

###3>抽象方法與抽象類

  子類能夠繼承父類的一些屬性方法,但是很多子類對於父類的這個方法可能有很多不同的值,這時就可以不將父類中的這個方法定死,即寫一個抽象類,將這個方法變成抽象方法,在子類中呼叫這個抽象方法並重寫,這樣就實現了子類繼承父類的特有的方法值。

規則:

	抽象用abstract來修飾
	抽象方法沒有方法體
	抽象方法必須在抽象類當中
	抽象類只能用作基類,無法例項化 
	抽象類中可以有非抽象成員
	抽象類的派生類必須實現抽象方法體
	父類是抽象類,子類繼承了這個類,必須把抽象類中的抽象方法重寫