vue分環境打包配置不同命令
C#是面向物件的語言,面向物件(Object Oriented,OO)是一種程式設計思想,強調系統的結構應該直接與現實世界的結構相對應,應該圍繞現實世界中的物件來構造系統,而不是圍繞功能來構造系統。
所有面向物件的語言都具有三個基本的特徵,它們是:
- 封裝:把客觀事物封裝成類,並將類內部實現隱藏,以保證資料的完整性。
- 繼承:通過繼承可以複用父類的程式碼。
- 多型:允許每個物件以適合自身的方式去響應共同的訊息。
C#中的面向物件程式設計指的是運用這三個基本的特徵來編寫程式。
封裝
封裝指的是把類的內部實現隱藏起來,不讓物件直接對其進行操作。C#提供了屬性機制對內部的狀態進行操作。在C#中,封裝可以通過public,protected,private,internal來體現。為什麼使用封裝,因為有的時候,我們把內部的資料定義為public之後,外部物件可以進行任意的操作,很可能導致不符合邏輯規則。面向物件的封裝特性,是一種保護狀態資料完整性的方法,在面向物件程式設計中,應更多的定義私有欄位,並且使用屬性機制來對私有欄位進行訪問。
封裝的好處是資料安全,提供重用性,分工合作和方便構建大型複雜的專案
繼承
在C#中,一個類可以繼承另外一個已有的類(密封類除外),被繼承的類稱為基類(或者父類),繼承的類稱為派生類,子類將獲得基類除建構函式和解構函式以外的所有成員。此外,靜態類也不能被繼承。通過繼承,程式可以實現對父類程式碼的複用。因為子類可以繼承父類的所有成員,父類中定義的程式碼便不需要在子類中重複定義了。
使用了繼承之後,當我們初始化一個子類時,除了會呼叫子類的建構函式之外,同時也會呼叫基類的建構函式,子類的初始化順序如下:
1:初始化類的例項欄位
2:呼叫基類的建構函式,若沒有基類,呼叫System.Object的建構函式。
3:呼叫子類的建構函式。
多型
由於可以繼承基類的成員,子類就有了相同的行為,但是有時子類的某些行為需要相互區別。子類需要覆蓋父類中的方法來實現子類特有的行為,這就是多型。多型即相同型別的物件呼叫相同的方法卻表現出不同行為的現象。當派生類從基類繼承時,它會獲得基類的所有方法、欄位、屬性和事件。面向物件的語言使用虛方法表達多型。若要更改基類的資料和行為,您有兩種選擇:可以使用新的派生成員替換基成員,或者可以重寫虛擬的基成員。
通過介面和抽象類實現多型
實踐中,可以通過介面和抽象類實現多型。
如下,多個不同的子類可以通過實現IExtend介面,實現對同一個方法有不同的行為。子類也可以通過override抽象父類的抽象方法從而實現不同的行為。但是可以注意到,我們在呼叫BasePhone的Video方法,會產生編譯報錯,即使我們例項化的是一個iPhone,具有Video方法,編譯器還是不能讀取到該資訊,因此我們需要用dynamic
class Program
{
static void Main(string[] args)
{
BasePhone phone = new iPhone();
phone.System();//執行時多型
//phone.Video(); 編譯報錯,這是因為編譯器的限制;實際在執行時是正確的
IExtend extend = new iPhone();
extend.Video();//執行時多型
//extend.Call() //
dynamic dPhone1 = phone; //通過dynamic關鍵字避開編譯器的檢查
dPhone1.Video();
dynamic dPhone2 = extend;
dPhone2.Call();
}
}
public interface IExtend
{
void Video();
}
public abstract class BasePhone
{
public void Call()
{
Console.WriteLine($"Use {this.GetType().Name} Call");
}
public abstract void System();
}
public class iPhone : BasePhone, IExtend
{
public void Video()
{
Console.WriteLine($"{this.GetType().Name} Video");
}
public override void System()
{
Console.WriteLine($"{this.GetType().Name} System is IOS");
}
}
public class Mi : BasePhone, IExtend
{
public void Video()
{
Console.WriteLine($"{this.GetType().Name} Video");
}
public override void System()
{
Console.WriteLine($"{this.GetType().Name} System is Android");
}
}
那麼,在實踐過程中,如何選擇抽象類和介面呢?
我們需要了解抽象類和介面的特點。對於介面而言,是約束,多實現,更加靈活,語義方面有點像:can do,可以說“實現介面的子類 can do 介面約束”。抽象類 是父類+約束,可完成通用的實現,只能單繼承,語義方面有點像: is a,可以說“子類is a 父類”。
因此,有的子類有,有的子類沒有的情況,就要考慮用介面。
選擇介面還是抽象類的原則:子類都一樣的,放在父類;子類都有但是不同,放在父類抽象一下;有的子類有,有的子類沒有,那就用介面。
一般情況,介面用的更多,因為介面更簡單靈活 除非有些共有的需要繼承。
抽象方法和虛方法的區別和選擇?
最本質的區別:虛方法帶有實現(方法體),可以被重寫;抽象方法沒有實現,必須被重寫(override)。
在實踐中,虛方法,抽象方法在繼承中的行為也不同,如下所示。
class Program
{
static void Main(string[] args)
{
//虛方法/抽象方法,程式編譯時候,左邊遇到virtual/abstract時,做個標記,等程式執行的時候,判斷右邊是否有override,如果有,就以右邊為準
ParentClass parent = new Child();
parent.CommonMethod();//普通方法,父類為準;這個是編譯時確定的,特點是:效率高
parent.VirtualMethod1();//虛方法,子類沒過載,左邊為準
parent.VirtualMethod2();//虛方法,子類有過載,右邊為準;執行時確定,特點是為了靈活
parent.AbstractMethod();//抽象方法,右邊為準;執行時確定,特點是為了靈活
Console.Read();
}
}
public class Child : ParentClass
{
public override void VirtualMethod2()//子類過載了父類的 VirtualMethod2
{
Console.WriteLine("我是子類,過載虛方法2");
}
public sealed override void AbstractMethod() //sealed保證子類不能再重寫該方法
{
Console.WriteLine("我是子類,實現後的抽象方法");
}
}
public abstract class ParentClass
{
/// <summary>
/// 普通父類方法
/// </summary>
public void CommonMethod()
{
Console.WriteLine("我是父類,普通方法");
}
/// <summary>
/// 父類虛方法,必須包含實現,可以被過載
/// </summary>
public virtual void VirtualMethod1()
{
Console.WriteLine("我是父類,虛方法1");
}
public virtual void VirtualMethod2()
{
Console.WriteLine("我是父類,虛方法2");
}
/// <summary>
/// 我是抽象方法
/// </summary>
public abstract void AbstractMethod();
}
參考:
面向物件詳解
C#面向物件基本概念總結