面向對象有封裝、繼承、多態這三個特性,面向對象編程按照現實世界的特點來管理復雜的事物,把它們抽象為對象,具有自己的狀態和行為,通過對消息的反應來完成任務。這種編程方法提供了非常強大的多樣性,大大增加了代碼的重用機會,增加了程序開發的速度,將具備獨立性特制的程序代碼包裝起來,修改部分程序代碼時不至於會影響到程序的其他部分。
1.封裝
每個對象都包含它進行操作所需要的所有信息,封裝只公開代碼單元的對外接口,而隱藏其具體實現,盡量不對外公開代碼。使用封裝有很多好處,從設計角度來講,封裝可以對外屏蔽一些重要的信息,比如使用電腦的人只要知道怎麼使用電腦就可以,不用知道這些功能具體是怎麼實現的;從安全性考慮,封裝使對代碼的修改更加安全和容易,封裝明確的指出了哪些屬性和方法是外部可以訪問的,這樣當需要調整這個類的代碼時,只要保證公有屬性不變,公有方法的參數和返回值類型不變,那麼就可以盡情的修改這個類,而不會影響到程序的其他部分;封裝還避免了命名沖突的問題,封裝有隔離作用,不同的類中可以有相同名稱的方法和屬性,但不會混淆,也可以減少耦合。
2.繼承
繼承可以使用現有類的所有功能,並在無須重新編寫原來的類的情況下,對這些功能進行擴展。使用繼承而產生的類被稱為派生類或子類,而被繼承的類則稱為基類或超類或父類。繼承表示一個類型派生於一個基類型,它擁有該基類型的所有成員字段和函數,其子類是對父類的擴展;接口繼承是表示一個類型只繼承了函數的簽名,沒有繼承任何實現代碼。繼承劃分了類的層次性,也可以說繼承是對類的分組,父類代表的是抽象的類,更常用的類,而子類代表的是更為具體,更為細化的類;繼承是實現代碼重用、擴展的重要手段。所謂抽象的類是指與具體的事項相聯系,但只是表達整體而不是具體概念的類,比如說形狀包含正方形、長方形、圓等,這時候形狀是一個抽象的概念,相當於一個父類,而正方形、長方形、圓是具體的形狀,相當於是子類。
3.多態
多態是指程序中同名的不同方法共存的情況,主要通過子類對父類方法的覆蓋來實現多態。這樣,不同類的對象可以用同名的方法完成特定的功能,但具體的實現方法卻可以不同。比如說形狀包含正方形、長方形、圓等,每個形狀都有面積和周長,但是不同的形狀計算面積和周長的方法都不同。
下面就舉個例子來說明封裝、繼承、多態:
這個例子的基類,就是上面描述概念的時候提到的形狀,形狀是基類,而這個基類是個抽象的概念,而不是具體的,因此是抽象類,此類包含屬性形狀名稱、輸出形狀周長和面積的方法以及計算形狀周長和面積的抽象方法:
? 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 34 35 36 37 38 39 40 41 42 43/// <summary>
/// 形狀基類
/// </summary>
public
abstract
class
Shape
{
/// <summary>
/// 形狀名稱
/// </summary>
public
string
ShapeName {
get
;
private
set
; }
public
Shape(
string
shapeName)
{
ShapeName = shapeName;
}
/// <summary>
/// 輸出形狀周長
/// </summary>
public
virtual
void
PrintPerimeter(
double
perimeter)
{
Console.WriteLine(ShapeName +
" Perimeter: "
+ perimeter);
}
/// <summary>
/// 輸出形狀面積
/// </summary>
public
virtual
void
PrintArea(
double
area)
{
Console.WriteLine(ShapeName +
" Area: "
+ area);
}
/// <summary>
/// 計算形狀周長
/// </summary>
/// <returns></returns>
public
abstract
double
CalculatePerimeter();
/// <summary>
/// 計算形狀面積
/// </summary>
/// <returns></returns>
public
abstract
double
CalculateArea();
}
下面再來看具體的子類,子類是圓,包含屬性半徑、計算周長和面積的方法:
? 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 34/// <summary>
/// 圓
/// </summary>
public
class
Circle : Shape
{
/// <summary>
/// 圓的半徑
/// </summary>
public
double
R {
get
;
set
; }
public
Circle()
:
base
(
"Circle"
)
{
this
.R = 0;
}
/// <summary>
/// 圓的周長
/// </summary>
/// <returns></returns>
public
override
double
CalculatePerimeter()
{
return
2 * Math.PI * R;
}
/// <summary>
/// 圓的面積
/// </summary>
/// <returns></returns>
public
override
double
CalculateArea()
{
return
Math.PI * R * R;
}
}
再來看看長方形,包含屬性高度和寬度、計算周長和面積的方法:
? 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 34 35 36 37public
class
Rectangle : Shape
{
/// <summary>
/// 長方形的長度
/// </summary>
public
double
Width {
get
;
set
; }
/// <summary>
/// 長方形的高度
/// </summary>
public
double
Height {
get
;
set
; }
public
Rectangle()
:
base
(
"Rectangle"
)
{
Width = 0;
Height = 0;
}
/// <summary>
/// 長方形的周長
/// </summary>
/// <returns></returns>
public
override
double
CalculatePerimeter()
{
return
(Width + Height) * 2;
}
/// <summary>
/// 長方形的面積
/// </summary>
/// <returns></returns>
public
override
double
CalculateArea()
{
return
Width * Height;
}
}
以下是調用的代碼:
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21Circle circle =
new
Circle();
circle.R = 20;
Square square =
new
Square();
square.Edge = 10;
Rectangle rectangle =
new
Rectangle();
rectangle.Width = 20;
rectangle.Height = 30;
// 把子類賦給父類,能更好的體現多態性
IList<Shape> shapeList =
new
List<Shape>();
shapeList.Add(circle);
shapeList.Add(square);
shapeList.Add(rectangle);
foreach
(var shape
in
shapeList)
{
shape.PrintPerimeter(shape.CalculatePerimeter());
shape.PrintArea(shape.CalculateArea());
}
在此例子中,輸出形狀的周長和面積的方法沒有太大作用,是因為方法的具體實現比較簡單,如果是復雜的方法時會有很大作用。比如說想要實現拖拽功能,每個形狀都是可以拖拽的,而且每個形狀拖拽的方法都會是一樣的,但是想要實現拖拽功能可不像輸出這麼簡單,這時候子類可以繼承父類的方法,直接調用。