系列: Angelia
java
69 行
· 更新于 2026-09-27
Main.java
Angelia/Java/Week_6_7/code/03_inheritance_lsp/Main.java
/**
* 03_inheritance_lsp 示範程式。
*
* 編譯與執行:
* javac *.java
* java -ea Main
*/
public class Main {
/**
* 這個函式是「以 SavingsAccount 的契約為前提」寫的:
* 把餘額全部領出來——依契約,提領剛好等於餘額的金額一定成功,之後餘額為 0。
*/
static void withdrawEverything(SavingsAccount acct) {
int all = acct.getBalance();
boolean ok = acct.withdraw(all);
System.out.println(" 提領 " + all + " → 成功? " + ok
+ ",餘額 = " + acct.getBalance());
assert ok : "契約保證:提領等於餘額的金額必定成功";
assert acct.getBalance() == 0 : "契約保證:領光之後餘額為 0";
}
public static void main(String[] args) {
System.out.println("=== 1. 繼承與 super ===");
SavingsAccount s = new SavingsAccount();
s.deposit(100); // deposit 繼承自 BankAccount,沒有重寫
System.out.println(" withdraw(30) → " + s.withdraw(30) + ",餘額 " + s.getBalance());
System.out.println(" withdraw(500) → " + s.withdraw(500) + ",餘額 " + s.getBalance());
assert s.getBalance() == 70;
// BankAccount b = new BankAccount(); // 編譯錯誤:抽象類別不能實例化
System.out.println("=== 2. 動態分派:陣列裡每個物件跑自己的 withdraw ===");
BankAccount[] accounts = {
new SavingsAccount(), new LoggingSavingsAccount(), new AccountWithWithdrawalFees()
};
for (BankAccount a : accounts) {
a.deposit(100);
boolean ok = a.withdraw(100); // 靜態型別是 BankAccount,執行的卻是各子類別的版本
System.out.println(" " + a.getClass().getSimpleName()
+ ":存 100 領 100 → " + ok + ",餘額 " + a.getBalance());
}
System.out.println("=== 3. LoggingSavingsAccount:擴充而非取代 ===");
LoggingSavingsAccount l = new LoggingSavingsAccount();
l.deposit(50);
l.withdraw(20);
l.withdraw(999);
System.out.println(" log = " + l.getLog());
assert l.getLog().size() == 3;
l.getLog().clear(); // 改的是副本(防禦性複製)
assert l.getLog().size() == 3 : "外界不該能改到內部 log";
System.out.println("=== 4. LSP:合規的子型別可以放心替換 ===");
SavingsAccount good = new LoggingSavingsAccount();
good.deposit(80);
withdrawEverything(good); // OK
System.out.println("=== 5. LSP:違規的子型別會讓正確的程式碼出錯 ===");
SavingsAccount bad = new OverdraftSavingsAccount();
bad.deposit(80);
withdrawEverything(bad); // 這一步沒問題……
bad.withdraw(1000); // 但契約說不可能發生的事發生了:
System.out.println(" 再提 1000 → 餘額 = " + bad.getBalance() + "(負數!不變量被打破)");
if (bad.getBalance() < 0) {
System.out.println(" ★ 編譯器沒有抱怨,但以 SavingsAccount 契約為前提的程式碼全都可能出錯。");
}
System.out.println("全部完成。");
}
}
相关文章
Angelia
haskell
EN
更新于 2026-02-03
Adding.hs
Adding.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Adding.hs).
阅读文章 →
Angelia
haskell
EN
更新于 2026-02-03
Area.hs
Area.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Area.hs).
阅读文章 →
Angelia
haskell
EN
更新于 2026-02-03
Chess.hs
Chess.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Chess.hs).
阅读文章 →
Angelia
haskell
EN
更新于 2026-02-03
ChessGraphics.hs
ChessGraphics.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/ChessGraphics.hs).
阅读文章 →
Angelia
haskell
EN
更新于 2026-02-03
Examples.hs
Examples.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Examples.hs).
阅读文章 →
Angelia
haskell
EN
更新于 2026-02-03
Fibonacci.hs
Fibonacci.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Fibonacci.hs).
阅读文章 →