類別與物件
- 分類的意義
分類在物件導向中扮演重要的概念,通常我們要規畫一個系統可以物件根據特性或是屬性將他歸類到各個類別中,例如車子,不管是本田、賓士或BMW等等,它們都有共同的行為像加速、停止或是方向燈指示等等和共同的屬性像方向盤、輪胎和引擎。當我們將問題經由分析來歸類形成模組化。但是在我們將類別模組化的同時,我們需要保護裡面的資訊而不被任意更改,這種方式我們稱為封裝。
共同行為 | 共同屬性 |
加速 停止 方向燈指示 | 方向盤 引擎 車燈 |
- 封裝
封裝可以保護物件裡面的資訊也可以適當的提供外面物件使用,所以我們也會將封裝稱為資訊隱藏(information hiding),主要有兩個概念
1.將屬性或是方法封裝類別中,不給外面使用
2.適當控制物件的方法與屬性,來提供外部物件使用
我們學習如何建立一個類別並建立裡面的方法與屬性,以上面可以知道,車子共同的行為與方法,可以寫成下列類別來表達,我們可以稱之它為Car類別:
class Car
{
//屬性定義
public string stringWheel ;
public string light ;
//方法定義
public string Accelerate()
{
return "加速" ;
}
public string Stop()
{
return "停止" ;
}
}
當利用關鍵字new建立物件時,也表示該物件會在記憶體中佔據一個位子,這時也會對該物件做初步的參數初始化,所以我們會將一些可以需要初始化的參數或是方法封裝在特定的函式名稱中,我們建構子(constructor)。
建構子用法與限制 :
(1) 需要與類別名稱相同
(2) 可以接收參數但不可以有回傳值
(3) 可以多載建構子
(4) 當無建立建構子,編輯器會預設產生建構子。
class Car
{
private string color ;
private int speed ;
//建構子
public Car()
{
color = "black" ;
speed = 100 ;
}
//建構子-多載
public Car(string color,int speed)
{
this.color = color ;
this.speed = speed ;
}
}
當我們建立Car類別同時,也需建立該類別可以存取屬性和方法的範圍,我們可以從官方資料,以下這些資料,我們可以一一討論他們之間的關係
(1) public 公開修飾詞
以Car類別為例,當我們要呼叫Accelerate()方法時,首先要先在記憶體中建立分配一個空間給Car的物件,利用new關鍵字來建立實體物件,建立後會可以利用我們定義存取範圍來選擇適當的方法。由於上面的例子我們是利用public修飾詞做宣告,所以我們對Car類別沒有任何的限制,都可以做存取。
class Program
{
static void Main(string[] args)
{
//建立Car類別物件
Car BMW = new Car();
System.Console.WriteLine(BMW.Stop());
System.Console.WriteLine(BMW.Accelerate());
}
}
(2) private 修飾詞
當我們考慮到車子的配備時,方向盤與車燈有可能是車廠獨自有的品牌,我們宣告public修飾詞造成資訊隱藏不夠,這是我們需要利用private修飾詞來達到更進一步的封裝,所以我將Car類別做一下修改並定義可以由車廠來設定他們獨自車的配備。由於外部給予參數和內部設定參數wheel和light名稱相同,為了區別它們之間不同,我們必須利用this來完成內部屬性的建立
class Car
{
//共同屬性定義
private string wheel;
private string light;
//共同方法定義
public string Accelerate()
{
return "加速";
}
public string Stop()
{
return "停止";
}
//設定車子的配備
public void setCarEquipment(string wheel, string light)
{
this.wheel = wheel;
this.light = light;
}
}
class Program
{
static void Main(string[] args)
{
//建立Car類別物件
Car BMW = new Car();
BMW.setCarEquipment("米其林","BMW");
BMW.showCarEquipment();
}
}
結果:
(3)internal
1.將屬性或是方法封裝類別中,不給外面使用
2.適當控制物件的方法與屬性,來提供外部物件使用
- 類別的使用與定義
我們學習如何建立一個類別並建立裡面的方法與屬性,以上面可以知道,車子共同的行為與方法,可以寫成下列類別來表達,我們可以稱之它為Car類別:class Car
{
//屬性定義
public string stringWheel ;
public string light ;
//方法定義
public string Accelerate()
{
return "加速" ;
}
public string Stop()
{
return "停止" ;
}
}
- 建構子
當利用關鍵字new建立物件時,也表示該物件會在記憶體中佔據一個位子,這時也會對該物件做初步的參數初始化,所以我們會將一些可以需要初始化的參數或是方法封裝在特定的函式名稱中,我們建構子(constructor)。
建構子用法與限制 :
(1) 需要與類別名稱相同
(2) 可以接收參數但不可以有回傳值
(3) 可以多載建構子
(4) 當無建立建構子,編輯器會預設產生建構子。
class Car
{
private string color ;
private int speed ;
//建構子
public Car()
{
color = "black" ;
speed = 100 ;
}
//建構子-多載
public Car(string color,int speed)
{
this.color = color ;
this.speed = speed ;
}
}
- 存取範圍
當我們建立Car類別同時,也需建立該類別可以存取屬性和方法的範圍,我們可以從官方資料,以下這些資料,我們可以一一討論他們之間的關係
宣告存取範圍 | 意義 |
public | 存取沒有限制。 |
protected | 存取只限於繼承的衍生自包含類別的型別。 |
internal | 存取只限於目前的組件。 |
protected internal | 存取只限於目前的組件或衍生自包含類別的型別 |
private | 存取只限於包含類別。 |
(1) public 公開修飾詞
以Car類別為例,當我們要呼叫Accelerate()方法時,首先要先在記憶體中建立分配一個空間給Car的物件,利用new關鍵字來建立實體物件,建立後會可以利用我們定義存取範圍來選擇適當的方法。由於上面的例子我們是利用public修飾詞做宣告,所以我們對Car類別沒有任何的限制,都可以做存取。
class Program
{
static void Main(string[] args)
{
//建立Car類別物件
Car BMW = new Car();
System.Console.WriteLine(BMW.Stop());
System.Console.WriteLine(BMW.Accelerate());
}
}
(2) private 修飾詞
當我們考慮到車子的配備時,方向盤與車燈有可能是車廠獨自有的品牌,我們宣告public修飾詞造成資訊隱藏不夠,這是我們需要利用private修飾詞來達到更進一步的封裝,所以我將Car類別做一下修改並定義可以由車廠來設定他們獨自車的配備。由於外部給予參數和內部設定參數wheel和light名稱相同,為了區別它們之間不同,我們必須利用this來完成內部屬性的建立
class Car
{
//共同屬性定義
private string wheel;
private string light;
//共同方法定義
public string Accelerate()
{
return "加速";
}
public string Stop()
{
return "停止";
}
//設定車子的配備
public void setCarEquipment(string wheel, string light)
{
this.wheel = wheel;
this.light = light;
}
}
class Program
{
static void Main(string[] args)
{
//建立Car類別物件
Car BMW = new Car();
BMW.setCarEquipment("米其林","BMW");
BMW.showCarEquipment();
}
}
結果:
(3)internal
- 物件的生命周期
當我們宣告一個物件實體時,系統會建立該實體在記憶體中,當我們不再參考該物件
系統會自動的回收該物件的實體,釋放記憶體空間,
系統會自動的回收該物件的實體,釋放記憶體空間,
- 靜態方法與資料
用static所需宣告方法與資料的為靜態成員,當我們將方法或是資料宣告為靜態成員時,表示
記憶體中會預先載入這些成員,當所有物件要使用(參照)這些靜態成員,不需要用在額外宣告
,而且他只會共用一份相同的函式庫。所以靜態類別不能實體化,不能 使用 new 關鍵字建立類別型別的變數。
Ex:
class Math
{
}
[補充]
記憶體中會預先載入這些成員,當所有物件要使用(參照)這些靜態成員,不需要用在額外宣告
,而且他只會共用一份相同的函式庫。所以
Ex:
class Math
{
}
[補充]
- 匿名類別(anonymous)
匿名類別沒有類別名稱的類別,當然編譯器會替匿名取一個內部的名稱,才會進行編譯
。通常因為沒有型別,我們利用var宣告成隱含型變數。
*宣告方式
var anonName = new { Name="John" , Age=42 } ;
密封類別用來限制父類別不可以被子類別繼承,這種好處主要是限制類別繼承的深度,
Ex:
//宣告密封類別
sealed class SealedClass
{
public const double PI = 3.1415F;
public void work()
{
Console.WriteLine("密封類別不可以work繼承");
}
}
Ex: 繼承SealedClass,在編譯時會出現錯誤。
class SubSealedClass :SealedClass
{
}
當我們建造房子之前須要先去做藍圖的規劃,抽象類別通常是指一個想法或是架構,
但未有實體的建造規格。當我們需要規劃一些共同抽象行為或是屬性,通常我們會先去
規畫一個樣板(template)然後再由其他的子類別去override這些行為
Ex:
//制定房子的架構
abstract class HourseTemplate
{
private string _hourseType;
public string HourseType
{
get { return _hourseType; }
set { _hourseType = value; }
}
abstract protected void Length(double l); //長度
abstract protected void Width(double w); //寬度
abstract protected void Heigh(double h); //高度
abstract public double Volume(); //體積
abstract protected void Condition(string condition);
}
class Department:HourseTemplate
{
private double w;
private double l;
private double h;
private string condition;
public Department(double length, double width, double heigh)
{
Length(length);
Width(width);
Heigh(heigh);
}
protected override void Length(double l)
{
this.l = l;
}
protected override void Width(double w)
{
this.w = w;
}
protected override void Heigh(double h)
{
this.h = h;
}
public override double Volume()
{
return this.l * this.w * this.h;
}
protected override void Condition(string condition)
{
throw new NotImplementedException();
}
}
class Codominiun:HourseTemplate
{
private double w;
private double l;
private double h;
private string condition;
protected override void Length(double l)
{
this.l = l;
}
protected override void Width(double w)
{
this.w = w;
}
protected override void Heigh(double h)
{
this.h = h;
}
protected override void Condition(string condition)
{
this.condition = condition;
}
//自訂方法
public double Area()
{
return this.l * this.w ;
}
public override double Volume()
{
return this.l * this.w * this.h;
}
}
。通常因為沒有型別,我們利用var宣告成隱含型變數。
*宣告方式
var anonName = new { Name="John" , Age=42 } ;
- 封裝方法(setter, getter )
在實務上的應用,我們通常會用一個既定的模式去封裝物件,所謂setter就是屬性透過
public的修飾詞來做儲存資料方式,getter就是將封裝的資料取出。
[Net Framework 2.0] class Employee
{
private int _no ; private string _name ; public int No { set { this._no = value;} get { return value } } public int Name { set {this._name= value;} get { return value } } }
[Net Framework 3.5] class Employee { public int No { get ; set ; } public string Name { get ; set;} }
- 密封類別(sealed class)
密封類別用來限制父類別不可以被子類別繼承,這種好處主要是限制類別繼承的深度,
Ex:
//宣告密封類別
sealed class SealedClass
{
public const double PI = 3.1415F;
public void work()
{
Console.WriteLine("密封類別不可以work繼承");
}
}
Ex: 繼承SealedClass,在編譯時會出現錯誤。
class SubSealedClass :SealedClass
{
}
- 抽象類別(Abstract class)
當我們建造房子之前須要先去做藍圖的規劃,抽象類別通常是指一個想法或是架構,
但未有實體的建造規格。當我們需要規劃一些共同抽象行為或是屬性,通常我們會先去
規畫一個樣板(template)然後再由其他的子類別去override這些行為
Ex:
//制定房子的架構
abstract class HourseTemplate
{
private string _hourseType;
public string HourseType
{
get { return _hourseType; }
set { _hourseType = value; }
}
abstract protected void Length(double l); //長度
abstract protected void Width(double w); //寬度
abstract protected void Heigh(double h); //高度
abstract public double Volume(); //體積
abstract protected void Condition(string condition);
}
class Department:HourseTemplate
{
private double w;
private double l;
private double h;
private string condition;
public Department(double length, double width, double heigh)
{
Length(length);
Width(width);
Heigh(heigh);
}
protected override void Length(double l)
{
this.l = l;
}
protected override void Width(double w)
{
this.w = w;
}
protected override void Heigh(double h)
{
this.h = h;
}
public override double Volume()
{
return this.l * this.w * this.h;
}
protected override void Condition(string condition)
{
throw new NotImplementedException();
}
}
class Codominiun:HourseTemplate
{
private double w;
private double l;
private double h;
private string condition;
protected override void Length(double l)
{
this.l = l;
}
protected override void Width(double w)
{
this.w = w;
}
protected override void Heigh(double h)
{
this.h = h;
}
protected override void Condition(string condition)
{
this.condition = condition;
}
//自訂方法
public double Area()
{
return this.l * this.w ;
}
public override double Volume()
{
return this.l * this.w * this.h;
}
}
TestHourse.cs主程式
public static void Main()
{
Department department = new Department(50,50,1000);
department.HourseType = "大樓" ;
Console.WriteLine("{0}:{1}", department.HourseType, department.Volume());
}
{
Department department = new Department(50,50,1000);
department.HourseType = "大樓" ;
Console.WriteLine("{0}:{1}", department.HourseType, department.Volume());
}
留言
張貼留言