鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所

Slides:



Advertisements
Similar presentations
系統分析與設計 楊子青 H-1 H 、物件導向技術 n 物件導向的基本概念 – 物件、類別 – 封裝、繼承 – 同名異式 ( 多型 ) 、超荷 ( 過載 ) n 物件導向分析與設計及塑模工具 n UML 塑模工具.
Advertisements

3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
第10章 領域、概念與分析模型 10-1 再談物件導向分析 10-2 找出類別建立領域模型 10-3 指定責任建立概念模型
四資二甲 第三週作業 物件導向程式設計.
C#程序设计案例教程 第3章 程 序 结 构.
TQC+ 物件導向程式認證-JAVA.
第一章 面向对象程序设计.
第 5 章 流程控制 (一): 條件分支.
類別與物件 Class & Object.
第三章 控制结构.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
程式設計實作.
第5章 异常处理 王德俊 上海交通大学继续教育学院.
C#程序设计 c# programming 泛型 C#程序设计课程组.
第八章 C#高级编程.
H、物件導向技術 物件導向的基本概念 物件、類別 封裝、繼承 同名異式(多型) 、超荷(過載) 物件導向分析與設計及塑模工具 UML塑模工具.
第二章 C# 基础知识.
第四章 在 C# 中实现 OOP 概念.
程式敘述執行順序的轉移 控制與重複、方法 Lecturer:曾學文.
單元3:軟體設計 3-2 順序圖(Sequence Diagrams)
C 程式設計— 控制敘述 台大資訊工程學系 資訊系統訓練班.
第三章 C#面向对象初级编程 面向对象得程序设计越来越受到编程人员的喜爱。类和对象是面向对象程序设计中的重要概念。封装性、继承性和多态性是面向对象的特点,本章旨在全面说明C#编写面向对象程序设计的方法。
程式設計實作.
软件建模精要 面向对象软件建模技术.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
C#程序设计基础 $3 成员、变量和常量.
程序设计期末复习 黎金宁
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
JUDE教學 Jude安裝教學篇 Jude初步介紹篇 Jude繪圖介紹篇 介紹jude的安裝和下戴 介紹jude的初基本功能
第9章 多线程 王德俊 上海交通大学继续教育学院.
第9章 類別圖與物件圖 9-1 類別圖與物件圖的基礎 9-2 類別圖的符號 9-3 類別關係 9-4 物件圖 9-5 繪製類別圖與物件圖
第4章 物件導向分析與設計簡介 4-1 物件導向的軟體系統開發 4-2 物件導向分析與設計 4-3 UML的物件導向分析與設計
第4章 数组和集合 4.1 一维数组 4.2 二维数组 4.3 Array类 4.4 交错数组 4.5 ArrayList类
第三章 流程控制與例外處理 資訊教育研究室 製作 注意:本投影片僅供上課使用,非經同意,請勿散播或轉載。
C#面向对象程序设计 $7 继承和多态性.
實作輔導 3 日期: 4/14(星期六) 09:10~12:00、13:10~16:00
視窗程式設計 (Windows Programming)
UML类设计工具 任课老师:黄武 上午2时50分 10.
例外處理與 物件序列化(Exception Handling and Serialization of Objects)
檔案讀寫與例外處理 (File IO and Exception Handling)
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
C#程序设计基础 第二章 数据类型.
類別與物件 I (Classes and Objects I)
第三章 C# 基础知识.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
《JAVA程序设计》 语音答疑 辅导老师:高旻.
劉崇汎 崑山科技大學 電腦與通訊系 DLL的建立與引用 劉崇汎 崑山科技大學 電腦與通訊系
C#程序设计基础 $3 成员、变量和常量.
繼承與多型 (Inheritance and Polymorphism)
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
Java程式初體驗大綱 大綱 在學程式之前及本書常用名詞解釋 Hello Java!程式 在Dos下編譯、執行程式
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
第6章 面向对象开发的 分析与设计.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第二章 Java语法基础.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
目标 流程控制 字符串处理 C# 的类和对象 C# 访问修饰符 C# 构造函数和析构函数.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
C# 匿名委派 + Lambda + Func 建國科技大學 資管系 饒瑞佶.
PPT注意事项: 当前PPT课件文件必须和提供的源代码文件夹“代码”在同一目录中即不要移动文件夹“代码”的默认位置。
第2章 Java语言基础.
迴圈(重複性結構) for while do while.
C#快速導讀 流程控制.
判斷(選擇性敘述) if if else else if 條件運算子.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
第二章 Java基础语法 北京传智播客教育
第二章 Java基本语法 讲师:复凡.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
Presentation transcript:

鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所 物件導向程式設計 鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所 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版 物件導向二十一點模擬程式0.0.1版 物件導向二十一點模擬程式0.0.2版

物件導向程式設計 利用逐步細分法的函式導向程式設計曾經風行一時 物件和類別的觀念及程式語言普及之後,有必要採用不同的方式思考,以便更直截了當的寫出物件和類別的程式,並且充份發揮物件導向封裝、繼承、多型的特點

程式規劃 版本規劃 (80-20定律、要事第一、工程方法) 測試規劃 良好程式設計習慣 測試驅動方法開發 使用研發日誌,與夥伴合作,漸增式與回合式發展程式,維持可持續的發展步調,維護原始碼、註解、重要程式文件 測試驅動方法開發

物件導向程式設計之引入 版本規劃及測試規劃完成,要開始以漸增及回合方式,進行各個版本的進一步設計之時

物件導向思維 什麼是程式要完成的功能? 需要那些物件/類別才能完成程式功能? 物件/類別需要那些行為才能合作完成程式功能? 例: Mission Impossible, RPG 8

綱要 物件導向思維 CRC卡會議 UML類別圖 SRP:單一責任原理 物件導向二十一點模擬程式0.0.0版 物件導向二十一點模擬程式0.0.1版 物件導向二十一點模擬程式0.0.2版

CRC卡 Class (類別)、Responsibilities (負責功能)、Collaborators (合作類別) 由Kent Beck與Ward Cunningham發明,用以教導其同儕程式設計師物件導向的觀念 利用CRC卡會議可使初學者更容易了解物件與類別的意義

參考書籍 N. M. Wilkinson, Using CRC Cards: An Informal Approach to Object-Oriented Development, New York: SIGS Books, 1995. 11

練習 實際演練二十一點遊戲模擬原型的CRC卡會議 12

CRC卡會議 定義問題 產生類別 演練場景 整理卡片 13

產生類別 腦力激盪 過濾類別 初步建立繼承關係 描述類別 寫出類別名稱及定義 初步寫出負責功能(Responsibilities) 初步寫出資料成員(Attributes) 14

產生類別 腦力激盪 過濾物件/類別 建立繼承關係 描述類別

物件/類別之識別 流程敘述中的名詞、代名詞、名詞片語可能需要轉換為物件/類別(CRC卡) 類別之間的關係可以畫UML類別圖表示 主程式及類別的方法可以用虛擬碼進一步描述 16

資料成員與 類別之區分 資料成員通常表示類別的狀態變數,而非單獨之類別或型別 撲克牌之花色 借書資料之到期日期 但資料成員如可操作,且可用藍圖描述,可能可以構成一個類別,而資料成員變成一個物件 日期 17

必也正名乎 物件、類別、狀態、功能之名稱力求精準 使用一致命名規範 物件、類別、狀態:名詞片語 功能:動詞片語 條件判斷:形容詞片語、判斷句 多字連用,除第一字另外考慮外,各字開頭字母大寫 物件、狀態:第一個字小寫起頭 humanPlayer 類別、功能:第一個字大寫起頭 HumanPlayer 18

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

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

CRC卡正面 類別名稱 父類別 負責功能 合作類別 21

CRC卡背面 描述 成員變數 22

類別Card之CRC卡正面 類別名稱: Card 合作類別 負責功能 知道花色 知道點數 Deck Hand 23

類別Card之CRC卡背面 描述:代表用到的52張撲克牌 成員變數 花色(suit) 點數(rank) 24

類別Deck之CRC卡正面 類別名稱: Deck 合作類別 負責功能 知道剩下的牌 發一張牌 Game Card 25

類別Deck之CRC卡背面 描述:代表牌疊 成員變數 牌(cards) 26

類別 HumanPlayer之CRC卡正面 合作類別 負責功能 存入一張牌 知道玩家狀態 決定是否再要一張牌 傳回手牌總點數 Game Hand 27

類別HumanPlayer之CRC卡背面 描述:代表人類玩家 成員變數 手牌(hand) 玩家狀態(status) 28

類別Hand之 CRC卡正面 類別名稱: Hand 合作類別 負責功能 Card 知道手中的牌 知道手牌總點數 HumanPlayer ComputerPlayer 29

類別Hand之 CRC卡背面 描述:代表人類玩家或電腦玩家手中的牌 . 成員變數 牌(cards) 30

類別ComputerPlayer之 CRC卡正面 合作類別 負責功能 存入一張牌 知道玩家狀態 決定是否再要一張牌 傳回手牌總點數 Game Hand 31

類別 CRC卡背面 描述:代表電腦玩家. 成員變數 手牌(hand) 玩家狀態(status) 32

類別Game之CRC卡正面 類別名稱: Game 合作類別 負責功能 Deck 控制遊戲流程 比較電腦與人類玩家點數 HumanPlayer 大小 Deck HumanPlayer ComputerPlayer 33

類別Game之CRC卡背面 描述:代表整個二十一點遊戲. 成員變數 牌疊(deck) 人類玩家(humanPlayer) 電腦玩家(computerPlayer) 34

類別關係圖 HumanPlayer Game Deck Hand ComputerPlayer Card

綱要 物件導向思維 CRC卡會議 UML類別圖 SRP:單一責任原理 物件導向二十一點模擬程式0.0.0版 物件導向二十一點模擬程式0.0.1版 物件導向二十一點模擬程式0.0.2版

UML Unified Modeling Language 由Booch、Rumbaugh、Jacobson三人所創的物件導向軟體圖形表示標準 做為軟體系統的設計文件,使系統維護者容易了解修改程式,另一方面則是軟體工程的工具 背後有一套軟體工程架構,但只適合大規模軟體開發 小範圍程式設計,以較簡易具彈性的Agile Software Development比較實際好用 初學者只須了解幾種簡單的圖形,用來了解或記錄程式架構

UML繪製工具 Rational Rose JUDE-Community 可由UML圖形直接產生程式框架,並能保持程式與UML圖形的一致性,但價格相當昂貴 JUDE-Community 免費UML圖形繪製軟體 自2009年年底,JUDE-Community軟體已不再提供下載,改提供較進階的astah-Community http://jude.change-vision.com/jude-web/index.html 38

類別UML符號 39

UML 類別圖( Class Diagram ) 40

不同類別間傳送資料 類別的成員變數通常設為private,不能任意擷取 有人因此乾脆將所有成員變數宣告為public,方便取得,卻失去了使用類別封裝的原意 這種狀況,通常可以畫出類別圖,觀察可能的資料傳送路徑,再於相關類別使用適當的暫存變數或成員變數和成員函式,進行接力傳送資料

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

astah

用astah Community畫類別圖 File>New Diagram>Class Diagram 左下角>Base標籤>輸入類別名稱 左下角>Attribute標籤>Add按鈕>輸入資料狀態名稱、型別、可見度 左下角>Operation標籤>Add按鈕>輸入功能函式名稱、傳回值型別、可見度

用astah Community畫類別圖 工具列>Association符號旁箭頭>選擇所需Association符號 起點類別圖形按左鍵,轉折點按左鍵 終點類別圖形連按左鍵兩次 按起點、終點類別圖形調整位置 或按Shift鍵點選要對齊的圖形>Alignment>選擇調整方式 Edit>Copy to Clipboard>BMP, PNG File>Save As …

綱要 物件導向思維 CRC卡會議 UML類別圖 SRP:單一責任原理 物件導向二十一點模擬程式0.0.0版 物件導向二十一點模擬程式0.0.1版 物件導向二十一點模擬程式0.0.2版

單一責任原理 (SRP: Single-Responsibility Principle) A class should have only one reason to change 若某類別擔負多個責任,某一責任相關的改變會妨礙該類別其他責任的達成 何以不讓Game類別進行某一玩家是否為21點的計算? *Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003 47

一個違反SRP的例子 *Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003 48

符合SRP的設計 *Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003 49

綱要 物件導向思維 CRC卡會議 UML類別圖 SRP:單一責任原理 物件導向二十一點模擬程式0.0.0版 物件導向二十一點模擬程式0.0.1版 物件導向二十一點模擬程式0.0.2版

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

混充類別BlackJack_0_0_0.BlackJackTest using System; namespace BlackJack_0_0_0 { class BlackJackTest public static bool Scenario_1_OK() return true; }

綱要 物件導向思維 CRC卡會議 UML類別圖 SRP:單一責任原理 物件導向二十一點模擬程式0.0.0版 物件導向二十一點模擬程式0.0.1版 物件導向二十一點模擬程式0.0.2版

二十一點遊戲模擬v0.1流程 產生牌疊 電腦(莊家)向玩家(一人)及本身派發一張明牌 電腦向玩家及本身派發一張明牌 莊家詢問玩家是否加牌, 直至玩家不加牌或報到 莊家如不足 17點便需加牌直至超過或等於 17點 對未有爆煲或報到的玩家, 比點數大小, 大者勝, 如莊家爆煲, 玩家勝

二十一點遊戲模擬原型之測試規畫: 場景1 玩家 莊家 ♠A ♥J ♦10 勝

UML 類別圖( Class Diagram ) 56

Scenario 1: Sequence Diagram

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()); return (player.IsBlackJack()); }

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

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;

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

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

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;

BlackJack_0_0_1.ComputerPlayer 片段 Card[] hand = new Card[1]; int nCards = 0; public ComputerPlayer() { } public void SaveACard(Card card) { hand[nCards++] = card; }

綱要 物件導向思維 CRC卡會議 UML類別圖 SRP:單一責任原理 物件導向二十一點模擬程式0.0.0版 物件導向二十一點模擬程式0.0.1版 物件導向二十一點模擬程式0.0.2版

UML 類別圖

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()) return (player.GetStatus() == Status.BLACK_JACK && computer.GetStatus() == Status.PASS);

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

BlackJack_0_0_2.Status public enum Status { PASS = 0, BLACK_JACK = 1, BURST = 2 }

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

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;

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;

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;

BlackJack_0_0_2.HumanPlayer片段 (5/6) if (sum <= 21) { totalPoints = sum; }

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;

綱要 物件導向二十一點模擬程式0.0.3版 物件導向二十一點模擬程式0.0.4版

UML 類別圖

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

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

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

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; return suit_OK && rank_OK;

BlackJack_0_0_3.BlackJackTest. Game_OK public static bool Game_OK() { Console.WriteLine("Game 測試"); Game game = new Game(); game.Run(123); return true; }

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

BlackJack_0_0_3.Game.Play 片段 (1/3) player.SaveACard(deck.DealACard()); player.Dump(); computer.SaveACard(deck.DealACard()); computer.Dump(); if (IsBlackJackOrBurst()) return; while (player.GetStatus() == Status.PASS && player.WantOneMoreCard() && deck.HasMoreCard()) {

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(); Console.WriteLine("比大小分勝負");

BlackJack_0_0_3.Game.Play 片段 (3/3) if (IsBlackJackOrBurst()) return; if (computer.GetTotalPoints() >= player.GetTotalPoints()) { Console.WriteLine("電腦勝"); } else { Console.WriteLine("玩家勝"); }

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) Console.WriteLine("電腦 BlackJack!!!"); bool isBurst = false;

BlackJack_0_0_3.Game. IsBlackJackOrBurst 片段 (2/2) if (player.GetStatus() == Status.BURST) { isBurst = true; Console.WriteLine("玩家爆!!!"); } if (computer.GetStatus() == Status.BURST) Console.WriteLine("電腦爆!!!"); return (isBlackJack || isBurst);

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

BlackJack_0_0_3.Deck. PrepareDeck 片段 (1/2) bool[] used = new bool[52]; for (i = 0; i < 52; ++i) { used[i] = false; } pos = rand.Next() % 52; while (used[pos]) { ++pos; pos = pos % 52; s = pos / 13;

BlackJack_0_0_3.Deck. PrepareDeck 片段 (2/2) switch (s) { case 0: cards[i].suit = Suit.CLUB; break; . . . . . . default: } cards[i].rank = pos % 13 + 1; used[pos] = true;

BlackJack_0_0_3.Deck. DealACard & HasMoreCard public Card DealACard() { return cards[top++]; } public bool HasMoreCard() { return (top < 52);

BlackJack_0_0_3.HumanPlayer. WantOneMoreCard public bool WantOneMoreCard() { Console.Write("要再一張牌嗎? (y/n) "); string answer = Console.ReadLine(); return (answer == "Y" || answer == "y"); }

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

BlackJack_0_0_3.ComputerPlayer. WantOneMoreCard public bool WantOneMoreCard() { return (totalPoints < 17); }

綱要 物件導向二十一點模擬程式0.0.3版 物件導向二十一點模擬程式0.0.4版

重構(Refactoring) 不好的味道(Bad program flavor) 重構 重複出現的程式碼 不妥的名稱 擷取方法 重新命名 建立新類別 使用繼承

BlackJack_0_0_3重構: BlackJack_0_0_4 HumanPlayer與ComputerPlayer中有關判斷status的函式SetStaus、 JudgeStatus、Points完全相同 建立新類別StatusChecker,函式SetStaus, JudgeStatus, Points改成此一類別的靜態函式 SetStatus改名DetermineStatusAndTotalPoints,並修改參數 將列舉型別Status的宣告移到StatusChecker.cs

BlackJack_0_0_4.Status public enum Status { PASS = 0, BLACK_JACK = 1, BURST = 2 }

BlackJack_0_0_4.StatusChecker. DetermineStatusAndTotalPoints (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;

BlackJack_0_0_4.StatusChecker. DetermineStatusAndTotalPoints (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; }

BlackJack_0_0_4.HumanPlayer. SaveACard public void SaveACard(Card card) { hand[nCards++] = card; StatusChecker. DetermineStatusAndTotalPoints( hand, nCards, out status, out totalPoints); }