115 一般警察特考三等 警察資訊管理人員類別 物件導向程式設計 考古題詳解
第 一 題30 分
請說明物件導向語言中多型(polymorphism)之前提(使用情境)和功能,並須繪製統一塑模語言(UML)之類別圖,進而舉簡潔範例程式碼說明之。
登入後即可作答並保存紀錄。
核心觀念
本題考查物件導向程式設計的「多型(Polymorphism)」:同一個介面、父類別參考或方法呼叫,能依實際物件型別產生不同執行結果。
多型通常建立在下列前提:
-
共同抽象型別 多個類別具有共同的父類別或實作相同介面。
-
繼承或介面實作 子類別繼承父類別的方法,或實作介面所宣告的操作。
-
方法覆寫(Overriding) 子類別以相同方法簽章提供自己的實作。
-
父類別型別的參考變數 使用父類別或介面型別的變數,指向不同子類別所建立的物件。
-
動態繫結(Dynamic Binding) 執行時依物件的實際型別決定要呼叫哪一個覆寫方法。
多型的核心形式可表示為:
呼叫相同方法時:
例如,Animal 是父類別,Dog 與 Cat 是子類別。雖然程式以 Animal 型別呼叫 sound,但實際物件若為 Dog,便執行狗的叫聲;實際物件若為 Cat,便執行貓的叫聲。
多型的使用情境
多型適用於下列情境:
- 多個物件具有共同操作,但實際行為不同。
- 程式需要處理一群不同子類別物件。
- 希望新增子類別時,不必大幅修改既有的呼叫端程式。
- 透過抽象化降低模組間耦合。
- 實作可替換的元件,例如支付方式、資料庫連線、圖形物件、通知服務等。
例如,支付系統可定義共同介面 Payment,再由 CreditCardPayment、LinePayPayment、BankTransferPayment 分別實作 pay。結帳程式只需操作 Payment,不必知道實際使用哪一種支付方式。
多型的功能
1. 統一操作介面
不同類別可以透過共同的父類別或介面被一致處理。
例如:
Animal animal;
animal.sound;
呼叫端只需要知道物件具備 sound,不必依序判斷它是狗、貓或其他動物。
2. 實現行為差異化
相同的方法名稱可依不同子類別產生不同功能。
Dog.sound // 汪汪
Cat.sound // 喵喵
3. 提高可擴充性
新增 Bird 類別並覆寫 sound 後,原有的處理流程仍可使用,不需修改既有的多型呼叫架構。
4. 降低耦合
呼叫端依賴抽象型別,而非依賴具體類別,使系統更容易維護與替換。
5. 支援開放封閉原則
系統應「對擴充開放,對修改封閉」。新增子類別可擴充行為,既有程式碼不必因而大幅修改。
UML 類別圖
以下以 Animal、Dog、Cat 說明執行時多型:
<<abstract>>
Animal
--------------------------------
+ sound: void
--------------------------------
△
│ 繼承
┌────────┴────────┐
│ │
Dog Cat
---------------- ----------------
+ sound: void + sound: void
---------------- ----------------
若以 UML 標準表示:
- 空心三角形箭頭指向父類別
Animal。 Dog與Cat繼承Animal。sound在父類別中宣告,在子類別中覆寫。Animal標示為抽象類別,代表其主要用途是提供共同規格,不直接建立一般動物物件。
範例程式碼
以下使用 Java 說明:
abstract class Animal {
public abstract void sound;
}
class Dog extends Animal {
@Override
public void sound {
System.out.println("汪汪");
}
}
class Cat extends Animal {
@Override
public void sound {
System.out.println("喵喵");
}
}
public class Main {
public static void main(String[] args) {
Animal a1 = new Dog;
Animal a2 = new Cat;
a1.sound; // 汪汪
a2.sound; // 喵喵
}
}
程式執行分析
Animal a1 = new Dog;
左側的 Animal 是參考變數型別,右側建立的實際物件是 Dog。
第 二 題30 分
請說明物件導向語言中介面(interface)之前提(使用情境)和功能,並須繪製統一塑模語言(UML)之類別圖,進而舉簡潔範例程式碼說明之。
登入後即可作答並保存紀錄。
核心觀念
本題考查物件導向程式設計中的「介面(Interface)」:介面的前提、使用情境、功能,以及介面與實作類別之間的 UML 關係。
介面可視為一份「共同規格」或「契約(contract)」:
- 規定類別必須提供哪些操作方法。
- 說明物件能做什麼,不限定物件如何完成。
- 實作介面的類別必須完成介面所宣告的抽象方法。
- 使用者端可依介面型別操作物件,不必依賴具體類別。
- 同一類別可實作多個介面,因此可補足單一繼承的限制。
介面主要涉及下列物件導向概念:
- 抽象化:只公開必要功能,隱藏具體實作。
- 封裝:將功能規格集中於介面,降低使用端對實作細節的依賴。
- 多型:以介面型別指向不同實作類別,呼叫相同方法時產生不同結果。
- 低耦合:高階模組依賴介面,不直接依賴具體類別。
- 替換性:只要類別符合介面規格,就能在相同使用情境中相互替換。
介面的前提與使用情境
一、存在多個具有共同能力的類別
當不同類別具有相同的功能需求,但內部實作方式不同,適合抽出共同介面。
例如:
Payable:可付款Printable:可列印Serializable:可序列化Loginable:可登入Vehicle:可行駛
汽車、機車、卡車的行駛方式不同,但都可具備「行駛」這項共同能力,因此可由相同介面規範。
二、呼叫端只需要知道功能,不需要知道實作細節
若服務使用者只需要呼叫 pay,不需要知道付款是透過信用卡、行動支付或轉帳完成,便可設計 Payment 介面。
如此可避免呼叫端直接依賴特定實作類別。
三、需要支援多型與可替換實作
程式可將不同實作物件放入同一個介面型別的變數,呼叫相同方法:
Payment payment;
payment = new CreditCardPayment;
payment.pay;
payment = new MobilePayment;
payment.pay;
payment 雖然宣告為 Payment,實際物件可以是不同類別,這就是介面多型。
四、需要讓一個類別具備多種能力
Java 類別只能繼承一個父類別,但可以實作多個介面:
class SmartPhone implements Camera, GPS, InternetDevice {
// 同時具備拍照、定位與上網能力
}
因此,介面適合描述「能力」或「角色」,而不是單純的父子分類。
介面的功能
一、定義共同操作規格
介面宣告方法名稱、參數與回傳型別,使各實作類別遵循相同標準。
interface Payment {
void pay(double amount);
}
上述程式表示所有付款類別都必須提供:
pay(double amount)
二、隱藏具體實作
介面只描述「做什麼」,不描述「怎麼做」。
interface Payment {
void pay(double amount);
}
信用卡付款與行動支付可採用不同演算法,但使用者只需要呼叫 pay。
三、提供多型
介面型別可參考不同實作類別:
Payment p1 = new CreditCardPayment;
Payment p2 = new MobilePayment;
兩個物件都可透過 Payment 型別使用,因此呼叫端不必修改主要流程。
四、降低耦合
高階程式碼依賴介面:
class OrderService {
private Payment payment;
public OrderService(Payment payment) {
this.payment = payment;
}
public void checkout(double amount) {
payment.pay(amount);
}
}
OrderService 不需要知道付款方式的具體類別,只要傳入符合 Payment 介面的物件即可。
五、便於擴充與測試
新增付款方式時,只需建立新的實作類別:
class BankTransferPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("銀行轉帳:" + amount);
}
}
原有的 OrderService 不必修改,符合開放封閉原則:
- 對擴充開放。
- 對修改封閉。
此外,測試時可傳入假的付款物件,測試訂單流程而不必真的進行付款。
UML 類別圖
以下以付款系統為例:
<<interface>>
Payment
-------------
+ pay(amount): void
△
│
- - - - - - -┼- - - - - -
│ │
│ │
+--------------------+ +------------------+
| CreditCardPayment | | MobilePayment |
+--------------------+ +------------------+
| + pay(amount): void| | + pay(amount):void|
+--------------------+ +------------------+
+----------------------+
| OrderService |
+----------------------+
| - payment: Payment |
+----------------------+
| + checkout(amount) |
+----------------------+
│
│ 依賴/關聯
└────────────── Payment
UML 符號說明
-
<<interface>>表示Payment是介面。 -
介面到實作類別的虛線空心三角箭頭 表示「實作(realization)」關係。
CreditCardPayment - - -▷ Payment
MobilePayment - - -▷ Payment
-
OrderService到Payment的關係 表示OrderService使用介面,而不是直接依賴某一個具體付款類別。 -
+表示 public 成員。 -
-表示 private 成員。
範例程式碼
以下使用 Java 說明:
第 三 題40 分
請以物件導向語言設計一個簡易文字模式介面的登入程式。
程式需包含一般使用者(User)與高階使用者(Vuser)二個類別。一般使用者類別內之資料需包含有使用者姓名(Name)、一般密碼(Passwd)。高階使用者類別內之資料需包含有使用者姓名(Name)、安全密碼(Vpasswd)、權限等級(Vp)。
其中密碼皆十個字元,然而安全密碼必須含有英文字母大寫、英文字母小寫和數字。
作答內容除程式碼外,亦須繪製統一塑模語言(UML)之類別圖。程式語言可採用 C++、C#、Java 或 Python,程式內變數與函數的命名必須具有可讀性,另亦須撰寫完整的程式碼來驗證程式執行的正確性。
登入後即可作答並保存紀錄。
核心觀念
本題主要考查:
- 類別與物件
User代表一般使用者。Vuser代表高階使用者。
- 繼承
Vuser繼承User,共用使用者姓名與密碼驗證功能。- 高階使用者再增加安全密碼及權限等級。
- 封裝
- 使用私有或受保護屬性保存姓名、密碼及權限。
- 透過方法完成登入與資料驗證,避免直接任意修改資料。
- 方法覆寫與多型
Vuser可覆寫登入方法,加入高階使用者專屬的安全密碼驗證。
- 密碼格式驗證
- 一般密碼長度必須為 10 個字元。
- 安全密碼除長度為 10 個字元外,還必須同時包含:
- 英文字母大寫
- 英文字母小寫
- 數字
UML 類別圖
┌──────────────────────────────┐
│ User │
├──────────────────────────────┤
│ - name: str │
│ - password: str │
├──────────────────────────────┤
│ + __init__(name, password) │
│ + login(input_password):bool│
│ + get_name: str │
│ + validate_password: bool │
└───────────────▲──────────────┘
│ 繼承
│
┌───────────────┴──────────────┐
│ Vuser │
├──────────────────────────────┤
│ - permission_level: int │
├──────────────────────────────┤
│ + __init__(name, │
│ secure_password, level) │
│ + login(input_password):bool│
│ + validate_secure_password│
│ : bool │
│ + get_permission_level:int│
└──────────────────────────────┘
UML 關係說明
Vuser與User為一般化/繼承關係。Vuser是User的特殊化類別。User負責一般使用者的姓名與一般密碼。Vuser增加權限等級,並使用更嚴格的安全密碼規則。
解題方法
本題採用 Python 實作,設計如下:
- 建立
User類別:
- 儲存使用者姓名。
- 儲存一般密碼。
- 建構物件時驗證密碼長度是否為 10。
- 透過
login方法進行登入驗證。
- 建立
Vuser類別:
- 繼承
User。 - 增加
permission_level權限等級。 - 建構物件時檢查安全密碼是否同時具有大寫、小寫及數字。
- 覆寫
login方法,完成高階使用者登入。
- 建立文字模式介面:
- 使用者輸入姓名與密碼。
- 程式在一般使用者與高階使用者名單中尋找。
- 驗證成功後顯示登入身分;高階使用者另顯示權限等級。
- 透過
run_validation_tests進行完整測試:
- 測試一般密碼長度。
- 測試安全密碼規則。
- 測試正確與錯誤密碼。
- 測試高階使用者權限。