物件導向程式設計

102
1 物物物物物物物物 物物物物物物物物 鄭鄭鄭 鄭鄭鄭 鄭鄭鄭鄭鄭鄭 鄭鄭鄭鄭鄭鄭 鄭鄭鄭鄭鄭鄭 鄭鄭鄭鄭鄭鄭 / / 鄭鄭鄭鄭鄭鄭鄭 鄭鄭鄭鄭鄭鄭鄭 / / 鄭鄭鄭鄭鄭鄭鄭 鄭鄭鄭 鄭鄭鄭鄭鄭鄭鄭 鄭鄭鄭

description

物件導向程式設計. 鄭士康 國立台灣大學 電機工程學系 / 電信工程研究所 / 資訊網路與多媒體研究所. 1. 綱要. 物件導向思維 CRC 卡會議 UML 類別圖 SRP: 單一責任原理 物件導向二十一點模擬程式 0.0.0 版 物件導向二十一點模擬程式 0.0.1 版 物件導向二十一點模擬程式 0.0.2 版. 綱要. 物件導向二十一點模擬程式 0.0.3 版 物件導向二十一點模擬程式 0.0.4 版. 綱要. 物件導向思維 CRC 卡會議 UML 類別圖 SRP: 單一責任原理 物件導向二十一點模擬程式 0.0.0 版 - PowerPoint PPT Presentation

Transcript of 物件導向程式設計

Page 1: 物件導向程式設計

11

物件導向程式設計物件導向程式設計

鄭士康鄭士康國立台灣大學國立台灣大學

電機工程學系電機工程學系 //電信工程研究所電信工程研究所 //資訊網路與多媒體研究所資訊網路與多媒體研究所

Page 2: 物件導向程式設計

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 版 版

Page 3: 物件導向程式設計

3

綱要8.8. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.30.0.3 版版9.9. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.40.0.4 版版

Page 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 版 版

Page 5: 物件導向程式設計

5

物件導向程式設計物件導向程式設計• 利用逐步細分法的函式導向程式設計曾經

風行一時 • 物件和類別的觀念及程式語言普及之後,

有必要採用不同的方式思考,以便更直截了當的寫出物件和類別的程式,並且充份發揮物件導向封裝、繼承、多型的特點

Page 6: 物件導向程式設計

6

程式規劃程式規劃• 版本規劃 (80-20 定律、要事第一、工程方法 )

• 測試規劃• 良好程式設計習慣

– 使用研發日誌,與夥伴合作,漸增式與回合式發展程式,維持可持續的發展步調,維護原始碼、註解、重要程式文件

• 測試驅動方法開發

Page 7: 物件導向程式設計

7

物件導向程式設計之引入物件導向程式設計之引入• 版本規劃及測試規劃完成,要開始以漸增

及回合方式,進行各個版本的進一步設計之時

Page 8: 物件導向程式設計

88

物件導向思維物件導向思維

• 什麼是程式要完成的功能什麼是程式要完成的功能 ??• 需要那些物件需要那些物件 //類別才能完成程式功類別才能完成程式功能能 ??

• 物件物件 //類別需要那些行為才能合作完類別需要那些行為才能合作完成程式功能成程式功能 ??

•例例 : Mission Impossible, RPG: Mission Impossible, RPG

Page 9: 物件導向程式設計

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 版 版

Page 10: 物件導向程式設計

10

CRCCRC 卡卡• Class ( 類別 )、 Responsibilities ( 負責

功能 )、 Collaborators ( 合作類別 )•由 Kent Beck與Ward Cunningham 發

明,用以教導其同儕程式設計師物件導向的觀念

• 利用 CRC 卡會議可使初學者更容易了解物件與類別的意義

Page 11: 物件導向程式設計

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.

Page 12: 物件導向程式設計

1212

練習練習• 實際演練二十一點遊戲模擬原型的實際演練二十一點遊戲模擬原型的 CRCCRC 卡卡

會議會議

Page 13: 物件導向程式設計

1313

CRCCRC 卡會議卡會議

定義問題

產生類別

演練場景

整理卡片

Page 14: 物件導向程式設計

1414

產生類別產生類別• 腦力激盪腦力激盪• 過濾類別過濾類別• 初步建立繼承關係初步建立繼承關係• 描述類別描述類別

– 寫出類別名稱及定義寫出類別名稱及定義– 初步寫出負責功能初步寫出負責功能 (Responsibilities)(Responsibilities)– 初步寫出資料成員初步寫出資料成員 (Attributes)(Attributes)

Page 15: 物件導向程式設計

15

產生類別產生類別

腦力激盪

過濾物件 / 類別

建立繼承關係

描述類別

Page 16: 物件導向程式設計

1616

物件物件 //類別之識別類別之識別• 流程敘述中的名詞、代名詞、名詞片語流程敘述中的名詞、代名詞、名詞片語

可能需要轉換為物件可能需要轉換為物件 //類別類別 (CRC(CRC卡卡 ))• 流程敘述中的動詞、動詞片語可能需要流程敘述中的動詞、動詞片語可能需要

轉換為物件轉換為物件 //類別的方法類別的方法 (CRC(CRC卡卡 ))• 需要相同方法的物件可以歸納出一個類需要相同方法的物件可以歸納出一個類別別 (CRC(CRC卡卡 ))

• 類別之間的關係可以畫類別之間的關係可以畫 UMLUML 類別圖表類別圖表示示

• 主程式及類別的方法可以用虛擬碼進一主程式及類別的方法可以用虛擬碼進一步描述步描述

Page 17: 物件導向程式設計

17

資料成員與 類別之區分資料成員與 類別之區分• 資料成員通常表示類別的狀態變數,而非資料成員通常表示類別的狀態變數,而非

單獨之類別或型別單獨之類別或型別– 撲克牌之花色撲克牌之花色– 借書資料之到期日期借書資料之到期日期

• 但資料成員如可操作,且可用藍圖描述,但資料成員如可操作,且可用藍圖描述,可能可以構成一個類別,而資料成員變成可能可以構成一個類別,而資料成員變成一個物件一個物件– 日期日期

17

Page 18: 物件導向程式設計

1818

必也正名乎必也正名乎• 物件、類別、狀態、功能之名稱力求精準物件、類別、狀態、功能之名稱力求精準• 使用一致命名規範使用一致命名規範

– 物件、類別、狀態:名詞片語物件、類別、狀態:名詞片語– 功能:動詞片語功能:動詞片語– 條件判斷:形容詞片語、判斷句條件判斷:形容詞片語、判斷句– 多字連用,除第一字另外考慮外,各字開頭字母大多字連用,除第一字另外考慮外,各字開頭字母大

寫寫– 物件、狀態:第一個字小寫起頭 物件、狀態:第一個字小寫起頭 humanPlayerhumanPlayer– 類別、功能:第一個字大寫起頭 類別、功能:第一個字大寫起頭 HumanPlayerHumanPlayer

Page 19: 物件導向程式設計

1919

演練場景演練場景• 列出場景清單列出場景清單• 逐一演練場景逐一演練場景• 寫下類別負責功能、合作類別、資料成員寫下類別負責功能、合作類別、資料成員• 先演練簡單場景先演練簡單場景• 複雜場景可能包括其他簡單場景複雜場景可能包括其他簡單場景• 例外場景押後演練例外場景押後演練

Page 20: 物件導向程式設計

2020

整理卡片整理卡片• 刪除沒用到的類別、方法成員、資料成員刪除沒用到的類別、方法成員、資料成員• 發現繼承結構發現繼承結構• 繪出類別圖繪出類別圖 (Class Diagram)(Class Diagram)

Page 21: 物件導向程式設計

2121

CRCCRC 卡正面卡正面類別名稱

父類別負責功能 合作類別

Page 22: 物件導向程式設計

2222

CRCCRC 卡背面卡背面描述

成員變數

Page 23: 物件導向程式設計

2323

類別類別 CardCard之之 CRCCRC 卡正面卡正面

類別名稱 : Card

負責功能

知道花色

知道點數

合作類別

Deck

Hand

Page 24: 物件導向程式設計

24

類別類別 CardCard之之 CRCCRC 卡背面卡背面

24

描述 : 代表用到的 52張撲克牌

成員變數

花色 (suit)

點數 (rank)

Page 25: 物件導向程式設計

2525

類別類別 DeckDeck之之 CRCCRC 卡正面卡正面

類別名稱 : Deck

負責功能

知道剩下的牌

發一張牌

合作類別

Game

Card

Page 26: 物件導向程式設計

26

類別類別 DeckDeck之之 CRCCRC 卡背面卡背面

26

描述 : 代表牌疊

成員變數

牌 (cards)

Page 27: 物件導向程式設計

2727

類別 類別 HumanPlayerHumanPlayer之之 CRCCRC卡正面卡正面

類別名稱 : HumanPlayer

負責功能

存入一張牌知道玩家狀態決定是否再要一張牌傳回手牌總點數

合作類別

Game

Hand

Page 28: 物件導向程式設計

28

類別類別 HumanPlayerHumanPlayer之之 CRCCRC卡背面卡背面

28

描述 : 代表人類玩家

成員變數

手牌 (hand)玩家狀態 (status)

Page 29: 物件導向程式設計

2929

類別類別 HandHand 之 之 CRCCRC 卡正面卡正面

類別名稱 : Hand

負責功能

知道手中的牌知道手牌總點數

合作類別

Card

HumanPlayer

ComputerPlayer

Page 30: 物件導向程式設計

30

類別類別 HandHand 之 之 CRCCRC 卡背面卡背面

30

描述 : 代表人類玩家或電腦玩家手中的牌 .

成員變數

牌 (cards)

Page 31: 物件導向程式設計

3131

類別類別 ComputerPlayerComputerPlayer 之 之 CRCCRC卡正面卡正面

類別名稱 : ComputerPlayer

負責功能

存入一張牌知道玩家狀態決定是否再要一張牌傳回手牌總點數

合作類別

Game

Hand

Page 32: 物件導向程式設計

32

類別 類別 CRCCRC 卡背面卡背面

32

描述 : 代表電腦玩家 .

成員變數

手牌 (hand)玩家狀態 (status)

Page 33: 物件導向程式設計

3333

類別類別 GameGame之之 CRCCRC 卡正面卡正面

類別名稱 : Game

負責功能

控制遊戲流程比較電腦與人類玩家點數 大小

合作類別

Deck

HumanPlayer

ComputerPlayer

Page 34: 物件導向程式設計

34

類別類別 GameGame之之 CRCCRC 卡背面卡背面

34

描述 : 代表整個二十一點遊戲 .

成員變數

牌疊 (deck)人類玩家 (humanPlayer)電腦玩家 (computerPlayer)

Page 35: 物件導向程式設計

35

類別關係圖類別關係圖

ComputerPlayer

Game Deck

HumanPlayer

Hand

Card

Page 36: 物件導向程式設計

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 版 版

Page 37: 物件導向程式設計

37

UMLUML• Unified Modeling Language • 由Booch、Rumbaugh、 Jacobson三人所創的物

件導向軟體圖形表示標準• 做為軟體系統的設計文件,使系統維護者容易了解修改程式,另一方面則是軟體工程的工具– 背後有一套軟體工程架構,但只適合大規模軟體開

發– 小範圍程式設計,以較簡易具彈性的 Agile

Software Development比較實際好用 • 初學者只須了解幾種簡單的圖形,用來了解或記錄程

式架構

Page 38: 物件導向程式設計

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

Page 39: 物件導向程式設計

3939

類別類別 UMLUML 符號符號

Page 40: 物件導向程式設計

4040

UML UML 類別圖類別圖 ( Class ( Class Diagram )Diagram )

Page 41: 物件導向程式設計

41

不同類別間傳送資料不同類別間傳送資料• 類別的成員變數通常設為 private ,不能任意擷取

• 有人因此乾脆將所有成員變數宣告為public ,方便取得,卻失去了使用類別封裝的原意

•這種狀況,通常可以畫出類別圖,觀察可能的資料傳送路徑,再於相關類別使用適當的暫存變數或成員變數和成員函式,進行接力傳送資料

Page 42: 物件導向程式設計

4242

練習練習• 以大富翁遊戲模擬為目標,規畫版本,進以大富翁遊戲模擬為目標,規畫版本,進行行 CRCCRC 卡會議,產生卡會議,產生 CRCCRC 卡,繪出卡,繪出UMLUML 類別圖類別圖

Page 43: 物件導向程式設計

43

astah

Page 44: 物件導向程式設計

44

用 astah Community 畫類別圖

• File>New• Diagram>Class Diagram• 工具列 > 點選Class符號 > 在工作區按左鍵

•左下角>Base標籤 > 輸入類別名稱•左下角>Attribute標籤>Add按鈕 > 輸入資料狀態名稱、型別、可見度

•左下角>Operation標籤>Add按鈕 >輸入功能函式名稱、傳回值型別、可見度

Page 45: 物件導向程式設計

45

用 astah Community 畫類別圖

• 工具列>Association符號旁箭頭 > 選擇所需 Association符號

•起點類別圖形按左鍵,轉折點按左鍵•終點類別圖形連按左鍵兩次•按起點、終點類別圖形調整位置• 或按 Shift鍵點選要對齊的圖形

>Alignment>選擇調整方式• Edit>Copy to Clipboard>BMP, PNG• File>Save As …

Page 46: 物件導向程式設計

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 版 版

Page 47: 物件導向程式設計

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

Page 48: 物件導向程式設計

4848

一個違反一個違反 SRPSRP 的例子的例子

*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003

Page 49: 物件導向程式設計

4949

符合符合 SRPSRP 的設計的設計

*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003

Page 50: 物件導向程式設計

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 版 版

Page 51: 物件導向程式設計

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()); } }}

Page 52: 物件導向程式設計

52

混充類別BlackJack_0_0_0.BlackJackT

estusing System;

namespace BlackJack_0_0_0

{

class BlackJackTest

{

public static bool Scenario_1_OK()

{

return true;

}

}

}

Page 53: 物件導向程式設計

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 版 版

Page 54: 物件導向程式設計

54

二十一點遊戲模擬 v0.1 流程1. 產生牌疊2. 電腦 (莊家 )向玩家 (一人 )及本身派發一張明

牌 3. 電腦向玩家及本身派發一張明牌 4. 莊家詢問玩家是否加牌 , 直至玩家不加牌或報到 5. 莊家如不足 17 點便需加牌直至超過或等於 17

點 6. 對未有爆煲或報到的玩家 , 比點數大小 , 大者勝 , 如莊家爆煲 , 玩家勝

Page 55: 物件導向程式設計

55

二十一點遊戲模擬原型之測試規畫:場景 1

玩家 莊家

♠A ♥J

♦10 勝

Page 56: 物件導向程式設計

5656

UML 類別圖 ( Class Diagram )

Page 57: 物件導向程式設計

57

Scenario 1: Sequence Diagram

Page 58: 物件導向程式設計

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());

}

Page 59: 物件導向程式設計

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++];

}

Page 60: 物件導向程式設計

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; }}

Page 61: 物件導向程式設計

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;

}

Page 62: 物件導向程式設計

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);

}

Page 63: 物件導向程式設計

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;}

Page 64: 物件導向程式設計

64

BlackJack_0_0_1.ComputerPlayer

片段 Card[] hand = new Card[1];

int nCards = 0;

public ComputerPlayer() { }

public void SaveACard(Card card) {

hand[nCards++] = card;

}

Page 65: 物件導向程式設計

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 版 版

Page 66: 物件導向程式設計

66

UML 類別圖

Page 67: 物件導向程式設計

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);

Page 68: 物件導向程式設計

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++];}

Page 69: 物件導向程式設計

69

BlackJack_0_0_2.Status

public enum Status {

PASS = 0,

BLACK_JACK = 1,

BURST = 2

}

Page 70: 物件導向程式設計

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();}

Page 71: 物件導向程式設計

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;}

Page 72: 物件導向程式設計

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;

Page 73: 物件導向程式設計

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; }

Page 74: 物件導向程式設計

74

BlackJack_0_0_2.HumanPlayer 片段 (5/6)

if (sum <= 21) { totalPoints = sum; } }}

Page 75: 物件導向程式設計

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;}

Page 76: 物件導向程式設計

76

綱要8.8. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.30.0.3 版版9.9. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.40.0.4 版版

Page 77: 物件導向程式設計

77

UML 類別圖

Page 78: 物件導向程式設計

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();

Page 79: 物件導向程式設計

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];

Page 80: 物件導向程式設計

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]++;}

Page 81: 物件導向程式設計

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;

Page 82: 物件導向程式設計

82

BlackJack_0_0_3.BlackJackTest.

Game_OKpublic static bool Game_OK() {

Console.WriteLine("Game 測試 ");

Game game = new Game();

game.Run(123);

return true;

}

Page 83: 物件導向程式設計

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();}

Page 84: 物件導向程式設計

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()) {

Page 85: 物件導向程式設計

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();

Page 86: 物件導向程式設計

86

BlackJack_0_0_3.Game.Play 片段 (3/3)

if (IsBlackJackOrBurst()) return;if (computer.GetTotalPoints() >= player.GetTotalPoints()) { Console.WriteLine("電腦勝 ");} else { Console.WriteLine("玩家勝 ");}

Page 87: 物件導向程式設計

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;

Page 88: 物件導向程式設計

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);

Page 89: 物件導向程式設計

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);}

Page 90: 物件導向程式設計

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;

Page 91: 物件導向程式設計

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;}

Page 92: 物件導向程式設計

92

BlackJack_0_0_3.Deck.DealACard & HasMoreCardpublic Card DealACard() {

return cards[top++];

}

public bool HasMoreCard() {

return (top < 52);

}

Page 93: 物件導向程式設計

93

BlackJack_0_0_3.HumanPlayer.

WantOneMoreCardpublic bool WantOneMoreCard() {

Console.Write("要再一張牌嗎 ? (y/n) ");

string answer = Console.ReadLine();

return (answer == "Y" || answer == "y");

}

Page 94: 物件導向程式設計

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);

Page 95: 物件導向程式設計

95

BlackJack_0_0_3.ComputerPlayer.

WantOneMoreCardpublic bool WantOneMoreCard() {

return (totalPoints < 17);

}

Page 96: 物件導向程式設計

96

綱要8.8. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.30.0.3 版版9.9. 物件導向二十一點模擬程式物件導向二十一點模擬程式 0.0.40.0.4 版版

Page 97: 物件導向程式設計

97

重構 (Refactoring)

• 不好的味道 (Bad program flavor)– 重複出現的程式碼– 不妥的名稱

• 重構– 擷取方法– 重新命名– 建立新類別– 使用繼承

Page 98: 物件導向程式設計

98

BlackJack_0_0_3 重構 : BlackJack_0_0_4

• HumanPlayer與 ComputerPlayer 中有關判斷status 的函式 SetStaus 、 JudgeStatus、 Points 完全相同

• 建立新類別 StatusChecker ,函式 SetStaus, JudgeStatus, Points改成此一類別的靜態函式

• SetStatus 改名DetermineStatusAndTotalPoints ,並修改參數

•將列舉型別 Status 的宣告移到StatusChecker.cs

Page 99: 物件導向程式設計

99

BlackJack_0_0_4.StatusBlackJack_0_0_4.Status

public enum Status {

PASS = 0,

BLACK_JACK = 1,

BURST = 2

}

Page 100: 物件導向程式設計

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;

Page 101: 物件導向程式設計

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; } }}

Page 102: 物件導向程式設計

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);}