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

Slides:



Advertisements
Similar presentations
主要内容 Java 的常用包 Java 的常用包 “ == ” 和 “ equals ” 的用法 “ == ” 和 “ equals ” 的用法 基本数据类型与引用类型 基本数据类型与引用类型 String 和 StringBuffer String 和 StringBuffer 对象的克隆( clone.
Advertisements

JAVA 编 程 技 术 主编 贾振华 2010年1月.
第一單元 建立java 程式.
项目7 面向对象高级.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
四資二甲 第三週作業 物件導向程式設計.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
第7章 C#函數與.NET Framework類別函數庫
C#程序设计 10软件1、2班 王槐彬 计算机工程学院.
類別與物件 Class & Object.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
第5章 面向对象程序设计 本章要点 5.1 面向对象程序设计概述 5.2 Java语言的面向对象程序设计 5.3 方法的使用和对象数组
程式設計概論 1.1 程式設計概論 程式語言的演進 物件導向程式 程式開發流程 1.2 C++開發工具
C#程序设计 c# programming 泛型 C#程序设计课程组.
物件導向程式設計 (Object-Oriented rogramming)
.NET 程式設計入門(使用 C#) 講師:鄧智鴻.
第二章 C# 基础知识.
第四章 在 C# 中实现 OOP 概念.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
Classes Lecturer: 曾學文.
CHAPTER 9 建構方法 ROBERT.
程式敘述執行順序的轉移 控制與重複、方法 Lecturer:曾學文.
第三章 C#面向对象初级编程 面向对象得程序设计越来越受到编程人员的喜爱。类和对象是面向对象程序设计中的重要概念。封装性、继承性和多态性是面向对象的特点,本章旨在全面说明C#编写面向对象程序设计的方法。
程式設計實作.
C++ with Managed Extensions
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
C#程序设计基础 $3 成员、变量和常量.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
類別(class) 類別class與物件object.
Methods 靜宜大學資工系 蔡奇偉副教授 ©2011.
C#面向对象程序设计 $7 继承和多态性.
第6章 继承和接口设计 6.1 继 承 6.2 多态性 6.3 抽象类 6.4 接口 6.5 接口在集合排序中的应用.
視窗程式設計 (Windows Programming)
例外處理與 物件序列化(Exception Handling and Serialization of Objects)
Java 程式設計 講師:FrankLin.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
JAVA 程式設計與資料結構 第四章 陣列、字串與數學物件.
C#程序设计基础 第二章 数据类型.
類別與物件 I (Classes and Objects I)
第一單元 建立java 程式.
標籤、按鈕、工具列、狀態列 (Labels, Buttons, Tool Strips, and Status Strips)
第三章 C# 基础知识.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
|07 函數.
C#程序设计基础 $3 成员、变量和常量.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
類別與方法 (Classes and Methods)
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
挑戰C++程式語言 ──第8章 進一步談字元與字串
第四章 类 4.1 基础知识 4.2 构造函数 4.3 方法 4.4 属性与索引 4.5 String类
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
OOP9 類別Class.
函數應用(二)與自定函數.
陣列與結構.
第 9 章 建構函式與解構函式.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
第6單元 6-1 類別的繼承 (Class Inheritance) 6-2 抽象類別 (Abstract Class)
辅导课程十二.
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
JAVA 程式設計與資料結構 第三章 物件的設計.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
Unix指令4-文字編輯與程式撰寫.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
方法(Method) 函數.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
InputStreamReader Console Scanner
Presentation transcript:

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

封裝(Encapsulation) 類別將狀態變數與功能函式封裝起來 通常狀態變數為私有(private) ,只供同類別之功能函式取用,不可以由類別外直接取用 避開同名變數問題 避免被不慎改動,破壞狀態的正確一致性 容易維護,不影響外界程式 功能函式可能公用(public) ,也可能私有 一類別至少有一公用函式,以便應用

類別Dice

新增類別程式 專案>加入類別>類別 輸入類別名稱.cs

DiceSimulation.Program片段 Dice dice = new Dice(); dice.Toss(); Console.WriteLine( "擲出"+dice.FaceValue );

DiceSimulation.Dice 片段 public class Dice { int faceValue = 1; Random rand = new Random(); public int FaceValue get { return faceValue; } set { faceValue = value; } } public void Toss() faceValue = rand.Next() % 6 + 1;

程序( Procedure )呼叫 *J. G. Brookshear, Computer Science – An Overview, 8th edition, Addison-Wesley, 2005

函式呼叫流程 static void Main(string[] args) { public class Dice { . . . public void Toss() faceValue = rand.Next() % 6 + 1; } dice.Toss(); } public class Random { . . . public int Next() }

資料型別 實值型別(Value Type) 參考型別(Reference Type) 結構(Structs) 數值(Numeric) 布林(bool) 使用者定義Structs 列舉(Enumerations) 參考型別(Reference Type) 字串(string) 物件(object)

堆疊(Stack)與堆積(Heap) Heap . Stack

實值型別儲存方式 堆疊(Stack) int x = 100; x 100

參考型別儲存方式 堆積(Heap) 堆疊(Stack) string x = “abc”; x 參考 ‘a’ ‘b’ ‘c’

物件(Object)觀念 dice1 dice1.faceValue 記憶體地址1 dice1.rand 函式Toss進入地址 dice2 記憶體地址2 dice2.rand 函式Toss進入地址 函式成員Toss進入點

物件的設定(Assignment) dice2 = dice1; dice1 dice1.faceValue 記憶體地址1 dice1.rand 函式Toss進入地址 dice2 dice2 = dice1; dice2.faceValue 記憶體地址2 dice2.rand 函式Toss進入地址 函式成員Toss進入點

存取修飾詞 public private protected internal

偵錯器的進一步應用 “逐步執行”與”不進入函式”的差別 目前類別與函式顯示 監看式的應用 呼叫堆疊的應用 即時運算視窗的應用

練習 宣告並測試以下類別

測試 軟體錯誤代價可能極為高昂 測試可以發現並改正程式錯誤 通過的測試越多, 程式越可靠

測試時機與風險

極端化程式設計 (Extreme Programming) 撰寫一個簡單的測試程式 編譯執行程式,看它失敗 增添恰能通過測試之程式碼並編譯偵錯 重整及消除冗餘程式碼並編譯偵錯 反覆進行上述步驟

測試驅動開發方式 (Test-Driven Development -TDD) 寫測試主程式, 呼叫測試函式, 建置, 看它失敗 寫測試類別, 加上測試函式, 重新建置, 看它失敗 撰寫欲測試的類別, 加上株段(stub)函式, 使通過建置, 但不通過測試 改寫株段函式, 通過建置與測試 以相同方式, 增加新測試

TDD 參考資料 P. Provost, “Test-driven development in .NET,” http://www.codeproject.com/KB/dotnet/tdd_in_dotnet.aspx

類別 Card

測試規畫 ♠A ♥J ♦10 ♣3

程式TestingCard.Program.cs using System; using System.Diagnostics; namespace TestingCard { class Program static void Main(string[] args) CardTest test = new CardTest(); Debug.Assert(test.Spade_A_OK()); }

程式TestingCard.CardTest.cs using System; namespace TestingCard { class CardTest public bool Spade_A_OK() Card card = new Card(); card.Suit = 's'; card.Rank = 1; return (card.Suit == 's' && card.Rank == 1); }

程式TestingCard.Card.cs using System; namespace TestingCard { public class Card { private char suit; private int rank; public char Suit { get { return suit; } set { suit = value; } } public int Rank { get { return rank; } set { rank = value; }

練習 完成類別Card的其他三個測試

練習 重新以TDD測試類別Car

CalculatorTest.Program片段 Calculator calculator = new Calculator(); Console.Write("輸入第一個數字: "); operand1 = int.Parse(Console.ReadLine()); Console.Write("輸入第二個數字: "); operand2 = int.Parse(Console.ReadLine()); result = calculator.Add(operand1,operand2); Console.WriteLine("{0} + {1} = {2} ", operand1, operand2, result);

CalculatorTest.Calculator 片段 public class Calculator { public int Add(int a, int b) int result = a + b; return result; } public int Subtract(int a, int b) int result = a - b; . . .

程序參數與區域變數 模組(Module)觀念 參數(Parameters, 或稱引數 Arguments) 程式碼重覆使用 程式共同開發 資料獨立 參數(Parameters, 或稱引數 Arguments) 形式參數(Formal Parameters) 真實參數(Actual Parameters) 區域變數(Local variables)

數學函數呼叫流程 double y = Math.Sqrt( 2.0 ); class Math { static double Sqrt( double x ) . . . return result; }

記憶配置 呼叫模組記憶區 區域變數 真實參數 結果變數 形式參數 被呼叫模組記憶區 區域變數 傳回值

函式傳回值 Program.Main() result calculator.Add() result return value

練習 設定operand值並利用Assert敘述改寫CalculatorTest程式

SwappingIntegers.Program 片段 int x = 3; int y = 5; Swap(ref x, ref y); Debug.Assert(x == 5 && y == 3); . . . static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; }

PassByReferenceAndOut.Program片段(1/2) double length = 100.0; Square s = new Square(); s.Side = length; double area1 = 0.0; double perimeter1 = 0.0; s.GetAreaAndPerimeter(ref area1, ref perimeter1); Console.WriteLine( "正方形邊長: {0}, 面積: {1}, 周長: {2}", length, area1, perimeter1);

PassByReferenceAndOut.Program片段(2/2) double area2; double perimeter2; s.GetAreaAndPerimeterUsingOut(out area2, out perimeter2); Console.WriteLine( "正方形邊長: {0}, 面積: {1}, 周長: {2}", length, area2, perimeter2);

PassByReferenceAndOut.Square 片段 public void GetAreaAndPerimeter( ref double area, ref double perimeter) { area = Math.Pow(a, 2); perimeter = 4.0 * a; } public void GetAreaAndPerimeterUsingOut( out double area, out double perimeter)

傳值, 傳址, out 參數 傳值參數傳遞( Pass by value ) 傳址參數傳遞( Pass by reference ) 初值設定問題

練習(1/3) 寫主程式Program.Main() 以傳值參數參照下一頁虛擬碼,寫一個函式Program.Swap()交換兩張牌位置 利用之前的Card類別,宣告兩張撲克牌Card物件 呼叫Program中的static函數Swap()交換兩張牌位置 以傳值參數參照下一頁虛擬碼,寫一個函式Program.Swap()交換兩張牌位置

練習(2/3) 函式Swap虛擬碼 Procedure Swap( card1, card2 ) 1. temp = card1; return card1 temp card2

練習(3/3) 將Swap函式之參數設為傳值參數 用Assert敘述測試兩張牌能否交換 將Swap函式之參數改為傳址參數,再試一次 利用偵錯器找出結果差異之原因

OverloadingDemo.Program 片段 Adder adder = new Adder(); int a = 3; int b = 5; Debug.Assert(adder.Add(a, b) == 8); double ad = 3.2; double bd = 5.1; Debug.Assert(adder.Add(ad, bd) == 8.3);

OverloadingDemo.Adder 片段 public int Add(int a, int b) { return (a + b); } public double Add(double a, double b)

DiceSimulation2.Program 片段 int seed = 123; Dice dice = new Dice(seed); dice.Toss(); Console.WriteLine( "擲出" + dice.FaceValue );

DiceSimulation2.Dice片段 public Dice() { rand = new Random(); Toss(); } public Dice(int seed) rand = new Random(seed);

建構函式與解構函式 (Constructor and Destructor) 預設建構函式(default constructor) 具參數之建構函式 檢驗參數範圍 解構函式

物件產生與消滅流程 static void main( string[] arg ) { public Dice(int seed) { . . . } Dice dice = new Dice( seed ); 物件宣告 物件生成 ~Dice() { . . . } } 刪除物件dice 離開主函式, 程式結束

練習 修改類別Card,改用建構函式設定初值,以屬性取得suit及rank

UsingThis.Program 片段 Time t = new Time(11, 30, 52); int hour; int min; int sec; t.GetTime(out hour, out min, out sec); Console.WriteLine( "現在時間{0} : {1} : {2}", hour, min, sec);

UsingThis.Time片段 public Time(int hour, int min, int sec) { bool paramsAreValid = hour >= 0 && hour < 24 && min >= 0 && min < 60 && sec >= 0 && sec < 60; if( paramsAreValid ) { this.hour = hour; this.min = min; this.sec = sec; } else { Console.WriteLine("Time建構式參數值不合理"); }

物件自我參考 this t 記憶體地址 hour min sec this GetTime()進入地址 函式成員GetTime進入點

類別TimeConversion

UsingStatic.Program片段 int hoursToMins = TimeConversion.HoursToMins(hours); int daysToHours = TimeConversion.DaysToHours(days); Console.WriteLine(hours + " hours = " + hoursToMins + " minutes"); Console.WriteLine(days + " days = " + daysToHours + " hours"); Test t1 = new Test(); Test t2 = new Test(); Console.WriteLine(Test.GetNConstructed + " Test objects were constructed");

UsingStatic.TimeConversion片段 public static class TimeConversion { private const int HOURS_PER_DAY = 24; private const int MINS_PER_HOUR = 60; public static int HoursToMins( int hours ) return hours*MINS_PER_HOUR; } public static int DaysToHours( int days ) return days*HOURS_PER_DAY;

UsingStatic.Test片段 public class Test { private static int nConstructed = 0; public Test() { ++nConstructed; } public static int GetNConstructed { get { return nConstructed; }

靜態成員與靜態類別 常數宣告 靜態成員應用場合 靜態函式Main 靜態類別應用場合

靜態成員的記憶配置 t1 記憶體地址1 函式Test()進入地址 t2 函式Test()進入地址 記憶體地址2 函式成員Test進入點 nConstructed 記憶體地址 函式成員 GetNConstructed進入點

練習 (1/2) 在類別Card內增加靜態成員函式,累計產生的Card物件數 寫一程式利用類別Card產生三張撲克牌,放在deck內,印出產生的牌數

練習 (2/2) 實作並測試一靜態類別EqSolver,內含兩靜態成員函式double Linear(double a, double b)及double Quadratic(double a, double b, double c)分別解一次方程式a x + b = 0及a x2 + b x + c = 0

UsingStruct.Program 片段 (1/2) struct Point2D { public int x; public int y; }

UsingStruct.Program 片段 (2/2) static void Main(string[] args) { Point2D pt = new Point2D(); Console.WriteLine( "Initial location = ({0},{1})", pt.x, pt.y); pt.x = 3; pt.y = 4; "Final location = ({0},{1})", pt.x, pt.y); }

StructVSClass.SPoint2D 片段 struct SPoint2D { public int x; public int y; public SPoint2D(int x, int y) this.x = x; this.y = y; }

StructVSClass.CPoint2D 片段 { public int x; public int y; public CPoint2D() x = 0; y = 0; } public CPoint2D(int x, int y) this.x = x; this.y = y;

StructVSClass.Program片段 (1/4) SPoint2D sPt1 = new SPoint2D(3, 4); SPoint2D sPt2 = new SPoint2D(); SPoint2D sPt3 = new SPoint2D(); sPt2 = sPt1; sPt3 = sPt1; Console.WriteLine("sPt1 = ({0}, {1})", sPt1.x, sPt1.y); Console.WriteLine("sPt2 = ({0}, {1})", sPt2.x, sPt2.y); Console.WriteLine("sPt3 = ({0}, {1})", sPt3.x, sPt3.y);

StructVSClass.Program 片段(2/4) CPoint2D cPt1 = new CPoint2D(3, 4); CPoint2D cPt2 = new CPoint2D(); CPoint2D cPt3 = new CPoint2D(); cPt2 = cPt1; cPt3 = cPt1; Console.WriteLine("cPt1 = ({0}, {1})", cPt1.x, cPt1.y); Console.WriteLine("cPt2 = ({0}, {1})", cPt2.x, cPt2.y); Console.WriteLine("cPt3 = ({0}, {1})", cPt3.x, cPt3.y);

StructVSClass.Program片段 (3/4) sPt1.x = 10; sPt1.y = 20; sPt2.x = 30; sPt2.y = 40; Console.WriteLine("sPt1 = ({0}, {1})", sPt1.x, sPt1.y); Console.WriteLine("sPt2 = ({0}, {1})", sPt2.x, sPt2.y); Console.WriteLine("sPt3 = ({0}, {1})", sPt3.x, sPt3.y);

StructVSClass.Program片段 (4/4) cPt1.x = 10; cPt1.y = 20; cPt2.x = 30; cPt2.y = 40; Console.WriteLine("cPt1 = ({0}, {1})", cPt1.x, cPt1.y); Console.WriteLine("cPt2 = ({0}, {1})", cPt2.x, cPt2.y); Console.WriteLine("cPt3 = ({0}, {1})", cPt3.x, cPt3.y);

結構 定義方式與類別相似 記憶配置於堆疊 適合使用於小型資料集合 減少記憶回收之負擔 不可自訂預設建構函式 成員變數不能直接設定初值 設值時直接複製資料成員內容 不支援繼承功能

類別物件記憶配置 cPt2 = cPt1; cPt1 cPt1.x 記憶體地址1 cPt1.y cPt2 cPt2.x 記憶體地址2 heap space

結構物件記憶配置 sPt1.x sPt1 sPt1.y sPt2 sPt2.x sPt2.y stack

練習 宣告並測試結構Student,其中包括學號、姓名、成績

UsingCopyConstructor.CPoint2D片段 public CPoint2D() { x = 0; y = 0; } public CPoint2D(int x, int y) this.x = x; this.y = y; public CPoint2D(CPoint2D p) x = p.x; y = p.y;

UsingCopyConstructor.Program片段 (1/2) CPoint2D cPt1 = new CPoint2D(3, 4); CPoint2D cPt2 = new CPoint2D( cPt1 ); CPoint2D cPt3 = new CPoint2D( cPt1 ); Console.WriteLine("cPt1 = ({0}, {1})", cPt1.x, cPt1.y); Console.WriteLine("cPt2 = ({0}, {1})", cPt2.x, cPt2.y); Console.WriteLine("cPt3 = ({0}, {1})", cPt3.x, cPt3.y);

UsingCopyConstructor.Program片段 (2/2) cPt1.x = 10; cPt1.y = 20; cPt2.x = 30; cPt2.y = 40; Console.WriteLine("cPt1 = ({0}, {1})", cPt1.x, cPt1.y); Console.WriteLine("cPt2 = ({0}, {1})", cPt2.x, cPt2.y); Console.WriteLine("cPt3 = ({0}, {1})", cPt3.x, cPt3.y);

淺層複製與深層複製 淺層複製(Shallow copy) 深層複製(Deep copy) 系統提供 只複製參考(Reference)地址 沒有新物件產生 深層複製(Deep copy) 程式師提供 產生新物件 應複製所有資料成員

練習 宣告並測試類別Student,其中包括學號、姓名、成績,仿照程式StructVSClass及UsingCopyConstructor分別使用設值與複製建構函式產生Student物件,觀察淺層複製與深層複製的差別

株段函式(Stub Functions)與 混充類別(Mock Classes) 初期測試用以確認呼叫方式正確 多數程式錯誤發生於函式呼叫 易寫 易建立 執行快速 產生確定結果 易確認呼叫方式正確

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

專案與方案 專案( Project ) 一個完整的應用程式或程式庫 方案( Solution ) 集合幾個專案的問題解決方案

二十一點遊戲模擬原型方案規畫 方案:BlackJack_0_0_1 專案:BlackJack_0_0_1 專案:TestingCard2 Program, BlackJackTest, Deck, HumanPlayer, ComputerPlayer, Hand, Card 專案:TestingCard2 Program, CardTest

BlackJack_0_0_1.Card 片段(1/2) public enum Suit { CLUB = 0, DIAMOND = 1, HEART = 2, SPADE = 3 }

BlackJack_0_0_1.Card 片段(2/2) public struct Card { public Suit suit; public int rank; public Card(Suit suit, int rank) this.suit = suit; this.rank = rank; }

新增專案TestingCard2 方案總管>(方案BlackJack_0_0_1)右鍵>加入>新增專案>儲存現有專案>專案命名(TestingCard2) 方案總管>(專案TestingCard2)參考>右鍵>加入參考>專案>(BlackJack_0_0_1) 撰寫主程式TestingCard2.Program 建立並實作類別CardTest 建置專案TestingCard2 設定專案TestingCard2為啟始專案 開始偵錯

TestingCard2.Program using System; using System.Diagnostics; namespace TestingCard2 { class Program static void Main(string[] args) Debug.Assert(CardTest.Spade_A_OK()); }

TestingCard2.CardTest using System; using BlackJack_0_0_1; namespace TestingCard2 { class CardTest public static bool Spade_A_OK() Card card = new Card(Suit.SPADE, 1); return (card.suit == Suit.SPADE && card.rank == 1); }

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

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

UML 類別圖( Class Diagram ) 92

Scenario 1: Sequence Diagram

Stepwise Refinement 演算法設計 Magic number 7 加減 2 逐層分解工作 各項工作依繁簡、重複性、可替代性決定是否寫為函式

IsBlackJack()結構圖(Structure Chart) 計算各牌點數 無A時判斷 Points()

追求簡單清楚的程式 選用簡單有效的演算法 選用簡單易修改的程式架構 消除多餘程式

BlackJack_0_0_1.Program using System; using System.Diagnostics; namespace BlackJack_0_0_1 { class Program static void Main(string[] args) Debug.Assert( BlackJackTest.Scenario_1_OK()); }

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 片段(1/2) private Card card1; private Card card2; private Card card3; private int nCards = 0; public Deck() { card1 = new Card(Suit.SPADE, 1); card2 = new Card(Suit.HEART, 11); card3 = new Card(Suit.DIAMOND, 10); nCards = 3; }

BlackJack_0_0_1.Deck 片段(2/2) public Card DealACard() { if (nCards == 3) { nCards--; return card1; } if (nCards == 2) { return card2; if (nCards == 1) { return card3;

BlackJack_0_0_1.HumanPlayer 片段(1/3) private Card card1; private Card card2; private int nCards = 0; public void SaveACard(Card card) { if (nCards == 0){ card1 = card; } if (nCards == 1){ card2 = card; ++nCards;

BlackJack_0_0_1.HumanPlayer片段 (2/3) public bool IsBlackJack() { int point1 = Points( card1.rank ); int point2 = Points( card2.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 card1; public ComputerPlayer() { } public void SaveACard(Card card) { card1 = card; }

練習 產生方案及專案BlackJack_0_0_2 複製類別BlackJack_0_0_1.Deck至BlackJack_0_0_2,並修改為BlackJack_0_0_2.Deck,使能同時供測試場景1、2之用 複製類別BlackJack_0_0_1.BlackJackTest至BlackJack_0_0_2,並增加函式Scenario_2_OK()以測試場景2 複製修改其他類別,使能同時測試場景1、2