物件導向程式設計
description
Transcript of 物件導向程式設計
11
物件導向程式設計物件導向程式設計
鄭士康鄭士康國立台灣大學國立台灣大學
電機工程學系電機工程學系 //電信工程研究所電信工程研究所 //資訊網路與多媒體研究所資訊網路與多媒體研究所
2
綱要1.1. 物件導向思維 物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖 類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
3
綱要8.8. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.30.0.3 版版9.9. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.40.0.4 版版
4
綱要1.1. 物件導向思維 物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖 類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
5
物件導向程式設計物件導向程式設計• 利用逐步細分法的函式導向程式設計曾經
風行一時 • 物件和類別的觀念及程式語言普及之後,
有必要採用不同的方式思考,以便更直截了當的寫出物件和類別的程式,並且充份發揮物件導向封裝、繼承、多型的特點
6
程式規劃程式規劃• 版本規劃 (80-20 定律、要事第一、工程方法 )
• 測試規劃• 良好程式設計習慣
– 使用研發日誌,與夥伴合作,漸增式與回合式發展程式,維持可持續的發展步調,維護原始碼、註解、重要程式文件
• 測試驅動方法開發
7
物件導向程式設計之引入物件導向程式設計之引入• 版本規劃及測試規劃完成,要開始以漸增
及回合方式,進行各個版本的進一步設計之時
88
物件導向思維物件導向思維
• 什麼是程式要完成的功能什麼是程式要完成的功能 ??• 需要那些物件需要那些物件 //類別才能完成程式功類別才能完成程式功能能 ??
• 物件物件 //類別需要那些行為才能合作完類別需要那些行為才能合作完成程式功能成程式功能 ??
•例例 : Mission Impossible, RPG: Mission Impossible, RPG
9
綱要1.1. 物件導向思維物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖 類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
10
CRCCRC 卡卡• Class ( 類別 )、 Responsibilities ( 負責
功能 )、 Collaborators ( 合作類別 )•由 Kent Beck與Ward Cunningham 發
明,用以教導其同儕程式設計師物件導向的觀念
• 利用 CRC 卡會議可使初學者更容易了解物件與類別的意義
1111
參考書籍參考書籍• N. M. Wilkinson, N. M. Wilkinson, Using CRC Cards: Using CRC Cards:
An Informal Approach to Object-An Informal Approach to Object-Oriented DevelopmentOriented Development, New York: , New York: SIGS Books, 1995.SIGS Books, 1995.
1212
練習練習• 實際演練二十一點遊戲模擬原型的實際演練二十一點遊戲模擬原型的 CRCCRC 卡卡
會議會議
1313
CRCCRC 卡會議卡會議
定義問題
產生類別
演練場景
整理卡片
1414
產生類別產生類別• 腦力激盪腦力激盪• 過濾類別過濾類別• 初步建立繼承關係初步建立繼承關係• 描述類別描述類別
– 寫出類別名稱及定義寫出類別名稱及定義– 初步寫出負責功能初步寫出負責功能 (Responsibilities)(Responsibilities)– 初步寫出資料成員初步寫出資料成員 (Attributes)(Attributes)
15
產生類別產生類別
腦力激盪
過濾物件 / 類別
建立繼承關係
描述類別
1616
物件物件 //類別之識別類別之識別• 流程敘述中的名詞、代名詞、名詞片語流程敘述中的名詞、代名詞、名詞片語
可能需要轉換為物件可能需要轉換為物件 //類別類別 (CRC(CRC卡卡 ))• 流程敘述中的動詞、動詞片語可能需要流程敘述中的動詞、動詞片語可能需要
轉換為物件轉換為物件 //類別的方法類別的方法 (CRC(CRC卡卡 ))• 需要相同方法的物件可以歸納出一個類需要相同方法的物件可以歸納出一個類別別 (CRC(CRC卡卡 ))
• 類別之間的關係可以畫類別之間的關係可以畫 UMLUML 類別圖表類別圖表示示
• 主程式及類別的方法可以用虛擬碼進一主程式及類別的方法可以用虛擬碼進一步描述步描述
17
資料成員與 類別之區分資料成員與 類別之區分• 資料成員通常表示類別的狀態變數,而非資料成員通常表示類別的狀態變數,而非
單獨之類別或型別單獨之類別或型別– 撲克牌之花色撲克牌之花色– 借書資料之到期日期借書資料之到期日期
• 但資料成員如可操作,且可用藍圖描述,但資料成員如可操作,且可用藍圖描述,可能可以構成一個類別,而資料成員變成可能可以構成一個類別,而資料成員變成一個物件一個物件– 日期日期
17
1818
必也正名乎必也正名乎• 物件、類別、狀態、功能之名稱力求精準物件、類別、狀態、功能之名稱力求精準• 使用一致命名規範使用一致命名規範
– 物件、類別、狀態:名詞片語物件、類別、狀態:名詞片語– 功能:動詞片語功能:動詞片語– 條件判斷:形容詞片語、判斷句條件判斷:形容詞片語、判斷句– 多字連用,除第一字另外考慮外,各字開頭字母大多字連用,除第一字另外考慮外,各字開頭字母大
寫寫– 物件、狀態:第一個字小寫起頭 物件、狀態:第一個字小寫起頭 humanPlayerhumanPlayer– 類別、功能:第一個字大寫起頭 類別、功能:第一個字大寫起頭 HumanPlayerHumanPlayer
1919
演練場景演練場景• 列出場景清單列出場景清單• 逐一演練場景逐一演練場景• 寫下類別負責功能、合作類別、資料成員寫下類別負責功能、合作類別、資料成員• 先演練簡單場景先演練簡單場景• 複雜場景可能包括其他簡單場景複雜場景可能包括其他簡單場景• 例外場景押後演練例外場景押後演練
2020
整理卡片整理卡片• 刪除沒用到的類別、方法成員、資料成員刪除沒用到的類別、方法成員、資料成員• 發現繼承結構發現繼承結構• 繪出類別圖繪出類別圖 (Class Diagram)(Class Diagram)
2121
CRCCRC 卡正面卡正面類別名稱
父類別負責功能 合作類別
2222
CRCCRC 卡背面卡背面描述
成員變數
2323
類別類別 CardCard之之 CRCCRC 卡正面卡正面
類別名稱 : Card
負責功能
知道花色
知道點數
合作類別
Deck
Hand
24
類別類別 CardCard之之 CRCCRC 卡背面卡背面
24
描述 : 代表用到的 52張撲克牌
成員變數
花色 (suit)
點數 (rank)
2525
類別類別 DeckDeck之之 CRCCRC 卡正面卡正面
類別名稱 : Deck
負責功能
知道剩下的牌
發一張牌
合作類別
Game
Card
26
類別類別 DeckDeck之之 CRCCRC 卡背面卡背面
26
描述 : 代表牌疊
成員變數
牌 (cards)
2727
類別 類別 HumanPlayerHumanPlayer之之 CRCCRC卡正面卡正面
類別名稱 : HumanPlayer
負責功能
存入一張牌知道玩家狀態決定是否再要一張牌傳回手牌總點數
合作類別
Game
Hand
28
類別類別 HumanPlayerHumanPlayer之之 CRCCRC卡背面卡背面
28
描述 : 代表人類玩家
成員變數
手牌 (hand)玩家狀態 (status)
2929
類別類別 HandHand 之 之 CRCCRC 卡正面卡正面
類別名稱 : Hand
負責功能
知道手中的牌知道手牌總點數
合作類別
Card
HumanPlayer
ComputerPlayer
30
類別類別 HandHand 之 之 CRCCRC 卡背面卡背面
30
描述 : 代表人類玩家或電腦玩家手中的牌 .
成員變數
牌 (cards)
3131
類別類別 ComputerPlayerComputerPlayer 之 之 CRCCRC卡正面卡正面
類別名稱 : ComputerPlayer
負責功能
存入一張牌知道玩家狀態決定是否再要一張牌傳回手牌總點數
合作類別
Game
Hand
32
類別 類別 CRCCRC 卡背面卡背面
32
描述 : 代表電腦玩家 .
成員變數
手牌 (hand)玩家狀態 (status)
3333
類別類別 GameGame之之 CRCCRC 卡正面卡正面
類別名稱 : Game
負責功能
控制遊戲流程比較電腦與人類玩家點數 大小
合作類別
Deck
HumanPlayer
ComputerPlayer
34
類別類別 GameGame之之 CRCCRC 卡背面卡背面
34
描述 : 代表整個二十一點遊戲 .
成員變數
牌疊 (deck)人類玩家 (humanPlayer)電腦玩家 (computerPlayer)
35
類別關係圖類別關係圖
ComputerPlayer
Game Deck
HumanPlayer
Hand
Card
36
綱要1.1. 物件導向思維 物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖 類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
37
UMLUML• Unified Modeling Language • 由Booch、Rumbaugh、 Jacobson三人所創的物
件導向軟體圖形表示標準• 做為軟體系統的設計文件,使系統維護者容易了解修改程式,另一方面則是軟體工程的工具– 背後有一套軟體工程架構,但只適合大規模軟體開
發– 小範圍程式設計,以較簡易具彈性的 Agile
Software Development比較實際好用 • 初學者只須了解幾種簡單的圖形,用來了解或記錄程
式架構
3838
UMLUML 繪製工具繪製工具• Rational RoseRational Rose
– 可由可由 UMLUML 圖形直接產生程式框架,並能保持程式圖形直接產生程式框架,並能保持程式與與 UMLUML 圖形的一致性,但價格相當昂貴圖形的一致性,但價格相當昂貴
• JUDE-CommunityJUDE-Community– 免費免費 UMLUML 圖形繪製軟體圖形繪製軟體 – 自 2009年年底, JUDE-Community軟體已不再提供下載,改提供較進階的 astah-Community
http://jude.change-vision.com/jude-web/http://jude.change-vision.com/jude-web/index.htmlindex.html
3939
類別類別 UMLUML 符號符號
4040
UML UML 類別圖類別圖 ( Class ( Class Diagram )Diagram )
41
不同類別間傳送資料不同類別間傳送資料• 類別的成員變數通常設為 private ,不能任意擷取
• 有人因此乾脆將所有成員變數宣告為public ,方便取得,卻失去了使用類別封裝的原意
•這種狀況,通常可以畫出類別圖,觀察可能的資料傳送路徑,再於相關類別使用適當的暫存變數或成員變數和成員函式,進行接力傳送資料
4242
練習練習• 以大富翁遊戲模擬為目標,規畫版本,進以大富翁遊戲模擬為目標,規畫版本,進行行 CRCCRC 卡會議,產生卡會議,產生 CRCCRC 卡,繪出卡,繪出UMLUML 類別圖類別圖
43
astah
44
用 astah Community 畫類別圖
• File>New• Diagram>Class Diagram• 工具列 > 點選Class符號 > 在工作區按左鍵
•左下角>Base標籤 > 輸入類別名稱•左下角>Attribute標籤>Add按鈕 > 輸入資料狀態名稱、型別、可見度
•左下角>Operation標籤>Add按鈕 >輸入功能函式名稱、傳回值型別、可見度
45
用 astah Community 畫類別圖
• 工具列>Association符號旁箭頭 > 選擇所需 Association符號
•起點類別圖形按左鍵,轉折點按左鍵•終點類別圖形連按左鍵兩次•按起點、終點類別圖形調整位置• 或按 Shift鍵點選要對齊的圖形
>Alignment>選擇調整方式• Edit>Copy to Clipboard>BMP, PNG• File>Save As …
46
綱要1.1. 物件導向思維 物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
4747
單一責任原理單一責任原理(SRP: Single-Responsibility (SRP: Single-Responsibility
Principle)Principle)• A class should have only one reason A class should have only one reason
to changeto change• 若某類別擔負多個責任,某一責任相關的若某類別擔負多個責任,某一責任相關的改變會妨礙該類別其他責任的達成改變會妨礙該類別其他責任的達成
• 何以不讓何以不讓 GameGame 類別進行某一玩家是否為類別進行某一玩家是否為2121 點的計算點的計算 ??
*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003
4848
一個違反一個違反 SRPSRP 的例子的例子
*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003
4949
符合符合 SRPSRP 的設計的設計
*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003
50
綱要1.1. 物件導向思維 物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖 類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
51
BlackJack_0_0_0.Program
using System;using System.Diagnostics;namespace BlackJack_0_0_0{ class Program { static void Main(string[] args) { Debug.Assert(
BlackJackTest.Scenario_1_OK()); } }}
52
混充類別BlackJack_0_0_0.BlackJackT
estusing System;
namespace BlackJack_0_0_0
{
class BlackJackTest
{
public static bool Scenario_1_OK()
{
return true;
}
}
}
53
綱要1.1. 物件導向思維 物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖 類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
54
二十一點遊戲模擬 v0.1 流程1. 產生牌疊2. 電腦 (莊家 )向玩家 (一人 )及本身派發一張明
牌 3. 電腦向玩家及本身派發一張明牌 4. 莊家詢問玩家是否加牌 , 直至玩家不加牌或報到 5. 莊家如不足 17 點便需加牌直至超過或等於 17
點 6. 對未有爆煲或報到的玩家 , 比點數大小 , 大者勝 , 如莊家爆煲 , 玩家勝
55
二十一點遊戲模擬原型之測試規畫:場景 1
玩家 莊家
♠A ♥J
♦10 勝
5656
UML 類別圖 ( Class Diagram )
57
Scenario 1: Sequence Diagram
58
BlackJack_0_0_1.BlackJackTest 片段
public static bool Scenario_1_OK()
{
Deck deck = new Deck();
HumanPlayer player = new HumanPlayer();
ComputerPlayer computer = new
ComputerPlayer();
player.SaveACard(deck.DealACard());
computer.SaveACard(deck.DealACard());
player.SaveACard(deck.DealACard());
return (player.IsBlackJack());
}
59
BlackJack_0_0_1.Deck 片段
private Card[] cards;
private int top;
public Deck() {
cards = new Card[3];
cards[0] = new Card(Suit.SPADE, 1);
cards[1] = new Card(Suit.HEART, 11);
cards[2] = new Card(Suit.DIAMOND, 10);
top = 0;
}
public Card DealACard() {
return cards[top++];
}
60
BlackJack_0_0_1.Card 片段public enum Suit {
CLUB = 0, DIAMOND = 1, HEART = 2, SPADE = 3}public struct Card { public Suit suit; public int rank; public Card(Suit suit, int rank) { this.suit = suit; this.rank = rank; }}
61
BlackJack_0_0_1.HumanPlayer 片段 (1/3)
private Card[] hand = new Card[2];
private int nCards = 0;
public HumanPlayer() {}
public void SaveACard(Card card) {
hand[nCards++] = card;
}
62
BlackJack_0_0_1.HumanPlayer片段 (2/3)
public bool IsBlackJack() {
int point1 = Points( hand[0].rank );
int point2 = Points( hand[1].rank );
bool isBlackJack =
(point1 + point2 == 21);
if (!isBlackJack && point1 == 1) {
point1 = 11;
isBlackJack = (point1 + point2 == 21);
}
63
BlackJack_0_0_1.HumanPlayer片段 (3/3)
if (!isBlackJack && point2 == 1) { point2 = 11; isBlackJack = (point1 + point2 == 21); } return isBlackJack;}private int Points(int rank){ int points = rank; if (rank > 10) points = 10; return points;}
64
BlackJack_0_0_1.ComputerPlayer
片段 Card[] hand = new Card[1];
int nCards = 0;
public ComputerPlayer() { }
public void SaveACard(Card card) {
hand[nCards++] = card;
}
65
綱要1.1. 物件導向思維 物件導向思維 2.2. CRCCRC 卡會議卡會議3.3. UMLUML 類別圖 類別圖 4.4. SRP:SRP: 單一責任原理單一責任原理5.5. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.00.0.0 版 版 6.6. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.10.0.1 版版7.7. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.20.0.2 版 版
66
UML 類別圖
67
BlackJack_0_0_2.BlackJackTest.
Scenario_1_OK 片段Card[] cards = { new Card(Suit.SPADE, 1), new Card(Suit.HEART, 11), new Card(Suit.DIAMOND, 10)};Deck deck = new Deck(cards);HumanPlayer player = new HumanPlayer();ComputerPlayer computer = new ComputerPlayer();
player.SaveACard(deck.DealACard()); computer.SaveACard(deck.DealACard()) player.SaveACard(deck.DealACard());return (player.GetStatus() == Status.BLACK_JACK && computer.GetStatus() == Status.PASS);
68
BlackJack_0_0_2.Deck 片段
private Card[] cards;private int top = 0;public Deck(Card[] card) { int nCards = card.Length; this.cards = new Card[nCards]; int i; for (i = 0; i < nCards; ++i) { this.cards[i] = card[i]; }}public Card DealACard() { return cards[top++];}
69
BlackJack_0_0_2.Status
public enum Status {
PASS = 0,
BLACK_JACK = 1,
BURST = 2
}
70
BlackJack_0_0_2.HumanPlayer 片段 (1/6)
private Card[] hand = new Card[3];private int nCards;private Status status;private int totalPoints;public HumanPlayer() { nCards = 0;}public void SaveACard(Card card) { hand[nCards++] = card; SetStatus();}
71
BlackJack_0_0_2.HumanPlayer 片段 (2/6)
public Status GetStatus() { return status;}public int GetTotalPoints() { return totalPoints;}private int Points(int rank) { int points = rank; if (rank > 10) points = 10; return points;}
72
BlackJack_0_0_2.HumanPlayer 片段 (3/6)
private void SetStatus() { int[] point = new int[nCards]; int i; int sum = 0; for (i = 0; i < nCards; ++i) { point[i] = Points(hand[i].rank); sum += point[i]; } status = JudgeStatus(sum); totalPoints = sum; if (status != Status.PASS) return; bool isWithAce = false;
73
BlackJack_0_0_2.HumanPlayer 片段 (4/6)
for (i = 0; i < nCards; ++i) { if (point[i] == 1) { isWithAce = true; break; } } if (isWithAce) { sum += 10; if (sum == 21) { status = Status.BLACK_JACK; }
74
BlackJack_0_0_2.HumanPlayer 片段 (5/6)
if (sum <= 21) { totalPoints = sum; } }}
75
BlackJack_0_0_2.HumanPlayer 片段 (6/6)
private Status JudgeStatus(int sum) { Status status; if (sum == 21) { status = Status.BLACK_JACK; } else if (sum > 21) { status = Status.BURST; } else { status = Status.PASS; } return status;}
76
綱要8.8. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.30.0.3 版版9.9. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.40.0.4 版版
77
UML 類別圖
78
BlackJack_0_0_3.Program.Main
片段Debug.Assert(BlackJackTest.DeckRandom_OK(), "Deck random mode test failed");Debug.Assert(BlackJackTest.Game_OK(), "Game test failed");Console.WriteLine();Console.WriteLine("21點遊戲開始 ");Game game = new Game();game.Run();
79
BlackJack_0_0_3.BlackJackTest.
DeckRandom_OK 片段 (1/3)Deck deck = new Deck(123);Card[] cards = new Card[52];int i;for (i = 0; i < 52; ++i) { cards[i] = deck.DealACard();}int[] nSuit = new int[4];int s;for (s = 0; s < 4; ++s) { nSuit[s] = 0;}int[] nRank = new int[13];
80
BlackJack_0_0_3.BlackJackTest.
DeckRandom_OK 片段 (2/3)int r;for (r = 0; r < 13; ++r) { nRank[r] = 0;}for (i = 0; i < 52; ++i) { switch (cards[i].suit) { case Suit.CLUB: nSuit[0]++; break; . . . . . . } nRank[cards[i].rank - 1]++;}
81
BlackJack_0_0_3.BlackJackTest.
DeckRandom_OK 片段 (3/3)bool suit_OK = true;for (s = 0; s < 4; s++) { if (nSuit[s] != 13) { suit_OK = false; break; }}bool rank_OK = true;for (r = 0; r < 13; r++) { if (nRank[r] != 4) { rank_OK = false; break; }}return suit_OK && rank_OK;
82
BlackJack_0_0_3.BlackJackTest.
Game_OKpublic static bool Game_OK() {
Console.WriteLine("Game 測試 ");
Game game = new Game();
game.Run(123);
return true;
}
83
BlackJack_0_0_3.Game 片段
private HumanPlayer player = new HumanPlayer();private ComputerPlayer computer = new ComputerPlayer();public void Run() { deck = new Deck(); Play();}public void Run(int seed) { deck = new Deck(seed); Play();}
84
BlackJack_0_0_3.Game.Play 片段 (1/3)
player.SaveACard(deck.DealACard());player.Dump(); computer.SaveACard(deck.DealACard());computer.Dump(); player.SaveACard(deck.DealACard());player.Dump();if (IsBlackJackOrBurst()) return; computer.SaveACard(deck.DealACard());computer.Dump();if (IsBlackJackOrBurst()) return;while (player.GetStatus() == Status.PASS && player.WantOneMoreCard() && deck.HasMoreCard()) {
85
BlackJack_0_0_3.Game.Play 片段 (2/3)
player.SaveACard(deck.DealACard()); player.Dump();}if (IsBlackJackOrBurst()) return;while ( computer.GetStatus() == Status.PASS &&
computer.WantOneMoreCard() && deck.HasMoreCard())
{ computer.SaveACard(deck.DealACard());
computer.Dump();}if (IsBlackJackOrBurst()) return;Console.WriteLine("比大小分勝負 ");player.Dump();computer.Dump();
86
BlackJack_0_0_3.Game.Play 片段 (3/3)
if (IsBlackJackOrBurst()) return;if (computer.GetTotalPoints() >= player.GetTotalPoints()) { Console.WriteLine("電腦勝 ");} else { Console.WriteLine("玩家勝 ");}
87
BlackJack_0_0_3.Game.IsBlackJackOrBurst 片段
(1/2)bool isBlackJack = false;if (player.GetStatus() == Status.BLACK_JACK){ isBlackJack = true; Console.WriteLine(" 玩家 BlackJack!!!");}if(computer.GetStatus()== Status.BLACK_JACK){ isBlackJack = true; Console.WriteLine(" 電腦 BlackJack!!!");}bool isBurst = false;
88
BlackJack_0_0_3.Game.IsBlackJackOrBurst 片段
(2/2)if (player.GetStatus() == Status.BURST){ isBurst = true; Console.WriteLine("玩家爆 !!!");}if (computer.GetStatus() == Status.BURST){ isBurst = true; Console.WriteLine("電腦爆 !!!");}return (isBlackJack || isBurst);
89
BlackJack_0_0_3.Deck 片段
private Card[] cards = new Card[52];private int top = 0;public Deck() { Random rand = new Random(); PrepareDeck(rand);}public Deck(int seed) { Random rand = new Random(seed); PrepareDeck(rand);}
90
BlackJack_0_0_3.Deck.PrepareDeck 片段 (1/2)
bool[] used = new bool[52];for (i = 0; i < 52; ++i) { used[i] = false;}for (i = 0; i < 52; ++i) { pos = rand.Next() % 52; while (used[pos]) { ++pos; pos = pos % 52; } s = pos / 13;
91
BlackJack_0_0_3.Deck.PrepareDeck 片段 (2/2)
switch (s) { case 0: cards[i].suit = Suit.CLUB; break; . . . . . . default: break; } cards[i].rank = pos % 13 + 1; used[pos] = true;}
92
BlackJack_0_0_3.Deck.DealACard & HasMoreCardpublic Card DealACard() {
return cards[top++];
}
public bool HasMoreCard() {
return (top < 52);
}
93
BlackJack_0_0_3.HumanPlayer.
WantOneMoreCardpublic bool WantOneMoreCard() {
Console.Write("要再一張牌嗎 ? (y/n) ");
string answer = Console.ReadLine();
return (answer == "Y" || answer == "y");
}
94
BlackJack_0_0_3.HumanPlayer.
Dump 片段Console.Write("玩家牌 : ");for (i = 0; i < nCards; ++i) { hand[i].Dump(); Console.Write("\t"); if ((i + 1) % 5 == 0) Console.WriteLine();}Console.WriteLine();Console.WriteLine("玩家總點數 : " + totalPoints);
95
BlackJack_0_0_3.ComputerPlayer.
WantOneMoreCardpublic bool WantOneMoreCard() {
return (totalPoints < 17);
}
96
綱要8.8. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.30.0.3 版版9.9. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.40.0.4 版版
97
重構 (Refactoring)
• 不好的味道 (Bad program flavor)– 重複出現的程式碼– 不妥的名稱
• 重構– 擷取方法– 重新命名– 建立新類別– 使用繼承
98
BlackJack_0_0_3 重構 : BlackJack_0_0_4
• HumanPlayer與 ComputerPlayer 中有關判斷status 的函式 SetStaus 、 JudgeStatus、 Points 完全相同
• 建立新類別 StatusChecker ,函式 SetStaus, JudgeStatus, Points改成此一類別的靜態函式
• SetStatus 改名DetermineStatusAndTotalPoints ,並修改參數
•將列舉型別 Status 的宣告移到StatusChecker.cs
99
BlackJack_0_0_4.StatusBlackJack_0_0_4.Status
public enum Status {
PASS = 0,
BLACK_JACK = 1,
BURST = 2
}
100
BlackJack_0_0_4.StatusCheckeBlackJack_0_0_4.StatusChecker.r.
DetermineStatusAndTotalPointDetermineStatusAndTotalPoints (1/2)s (1/2)public static void DetermineStatusAndTotalPoints(
Card[] hand, int nCards, out Status status, out int totalPoints) { int[] point = new int[nCards]; int sum = 0; for (i = 0; i < nCards; ++i) { point[i] = Points(hand[i].rank); sum += point[i]; } status = JudgeStatus(sum); totalPoints = sum; if (status != Status.PASS) return; bool isWithAce = false;
101
BlackJack_0_0_4.StatusCheckeBlackJack_0_0_4.StatusChecker.r.
DetermineStatusAndTotalPointDetermineStatusAndTotalPoints (2/2)s (2/2) for (i = 0; i < nCards; ++i) {
if (point[i] == 1) { isWithAce = true; break; } } if (isWithAce) { sum += 10; if (sum == 21) { status = Status.BLACK_JACK; } if (sum <= 21) { totalPoints = sum; } }}
102
BlackJack_0_0_4.HumanPlayer.BlackJack_0_0_4.HumanPlayer.SaveACardSaveACard
public void SaveACard(Card card) { hand[nCards++] = card; StatusChecker. DetermineStatusAndTotalPoints( hand, nCards, out status, out totalPoints);}