上一篇有講到封裝的特性,也就是把一個類別要運行操作所需用到的資訊都包在一起,其中這些資訊的存取權限設定就相對重要,透過修飾符就可以控制資訊能夠給誰使用、誰不能用,這樣就能提高系統的安全性與完整。(修飾符可以套在方法或是類別之前)
常見修飾符分為以下幾種:
class Employee {
int ID;
protected String name;
private int age;
public Employee(int id, String name, int age) {
ID = id;
this.name = name;
this.age = age;
}
public void selfIntrodution() {
System.out.println("我的名子叫" + name + ",今年" + age + "歲!");
}
}
class Engineer extends Employee{
private String position = "工程師"
}
public class Company {
public static void main(String []args) {
Engineer Jack = new Engineer(123, "Jack", 30);
Jack.selfIntrodution();
System.out.println(Jack.name);
System.out.println(Jack.age);
System.out.println(Jack.ID);
}
}
如上面的程式範例所示,我們宣告了Jack為工程師類別,呼叫了父類別的selfIntrodution()方法,修飾符為public,任何類別皆可存取,這行沒有問題。再來存取父類別的屬性(name),修飾符為protected,而它們的關係是父子類別,這行也沒有問題。接著試著去存取父類別的屬性(age),修飾符為private,這表示只有父類別自己本身才能存取的屬性,子類別沒有存取的權限,所以編譯會有錯誤,Jack能存取的private屬性只有自己的position。最後去存取父類別的屬性(ID),沒有特定的修飾符,表示所有在此package的類別皆可存取,這行也就沒有問題。
關於抽象類別有幾個重點:
abstract class Employee {
protected int ID;
protected String name;
protected int age;
public Employee(int id, String name, int age) {
ID = id;
this.name = name;
this.age = age;
}
abstract void selfIntrodution();
}
class Engineer extends Employee{
public Engineer(int id, String name, int age) {
super(id, name, age);
}
public void selfIntrodution() {
System.out.println("我是一位工程師");
}
}
class Accountant extends Employee{
public Accountant(int id, String name, int age) {
super(id, name, age);
}
public void selfIntrodution() {
System.out.println("我是一位會計師");
}
}
我在員工類別前面加了「abstract」,這就代表這是一個抽象類別,而抽象類別可以擁有抽象方法(selfIntrodution()),它可以不用去定義它的實作方式,要在子類別去複寫。
認識了抽象類別後,一定要在認識一下介面(Interface),介面封裝了一些特定的功能,只要有類別實作此介面,就可以使用介面所有的屬性和方法,現在請看以下範例程式碼:
interface habit {
void interest();
}
abstract class Employee {
protected int ID;
protected String name;
protected int age;
public Employee(int id, String name, int age) {
ID = id;
this.name = name;
this.age = age;
}
abstract void selfIntrodution();
}
class Engineer extends Employee implements habit{
public Engineer(int id, String name, int age) {
super(id, name, age);
}
public void selfIntrodution() {
System.out.println("我是一位工程師");
}
public void interest() {
System.out.println("我愛寫程式");
}
}
class Kid implements habit {
public void interest() {
System.out.println("我愛看電視");
}
}
public class Program {
public static void main(String []args){
Engineer Jack = new Engineer(123, "Jack", 30);
Kid Connie = new Kid();
Jack.interest();
Connie.interest();
}
}
// result:
// 我愛寫程式
// 我愛看電視
我們可以看到工程師類別除了繼承了員工類別外,還實作了習慣介面,另外小孩類別也實作了習慣介面,兩個類別分別定義了介面的方法(interest()),分別是「我愛寫程式」與「我愛看電視」。
看到這裡也許會有個疑問:已經有了抽象類別封裝好共同需要的屬性與方法,為甚麼還需要再多個介面來封裝呢?
答案就是當我們有兩個以上的具體類別,但它們卻不屬於同一類別,就像是程式範例一樣,工程師屬於員工的一種,所以它繼承了員工的屬性;而小孩卻不屬於任何類別,但卻又與工程師擁有「習慣」,因此我們把習慣寫成介面,並讓他們兩個可以實作。換句話說,當我們在設計程式的時候,若有發現不同的類別有重複的內容,那就可以把這些重複的內容封裝到抽象類別中,然後再由這些類別(子類別)去繼承抽象類別(父類別);而介面是發現不同父類別中的子類別之間,有重複的特徵,因此把這些特徵封裝到介面裡,再由這些子類別去實作。
簡單來說,此特徵是在不同類的物件發生,那就用介面實作;若在相似的類別發生,就用抽象類別去繼承。
有父類別的概念後,我們就可以不用再一直寫相同的程式碼在不同的類別上,而且修改父類別,子類別也會跟著修改,就不需要每一個類別都改過,維護程式就變得簡單多了;了解了修飾符後,可以讓類別封裝得更加完整、更具安全性。
物件導向的基本概念就介紹到這邊,接下來會說明在學習 Design Pattern 前需要了解的一些知識,這樣就可以在學習的時候更快了解 Pattern 的架構與應用方式。
除此之外,也歡迎大家走走逛逛關於我們團隊夥伴的文章
lu23770127 - SASS 基礎初學三十天
10u1 - 糟了!是世界奇觀!
juck30808 - Python - 數位行銷分析與 Youtube API 教學
SiQing47 - 前端?後端?你早晚都要全端的,何不從現在開始?