首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 應用程式架構組織實戰:以形狀遊戲示範命名空間、繼承與多型

     編輯:關於C語言

前言

在前一節我們介紹了如何組織應用程式結構,本文將透過一個綜合範例來實際演練。這個小遊戲雖然功能簡單,卻涵蓋了命名空間劃分、多類別定義、動態連結庫(DLL)跨檔案呼叫、例外處理、類別繼承、虛擬方法覆寫、多型實作等核心概念。建議讀者細讀程式碼,加深對基本觀念的理解。

遊戲規則與設計

程式是一個小型圖形遊戲:系統隨機產生矩形、正方形、直角三角形、等腰直角三角形四種圖形。玩家初始擁有 1000 分,每回合自行下注,根據下注額與隨機圖形面積計算贏得分數。程式使用 System.Random 類別產生隨機數。

原始碼架構說明

整個專案分為五個原始檔,分別編譯為兩個 DLL 及一個執行檔:

  • MyShape.cs:定義基底類別 Shape,包含虛擬方法 Draw() 與 GetArea()。
  • rect.cs:繼承 Shape 實作 Rectangle(矩形)與 Square(正方形),覆寫面積計算與繪製邏輯。
  • triangle.cs:定義 Triangle(一般三角形)做為基底,再衍生 RectTriangle(直角三角形)與 RectEqualTriangle(等腰直角三角形),展示多層繼承與 new 關鍵字隱藏基底欄位。
  • Mymessage.cs:封裝遊戲歡迎畫面與繼續詢問邏輯,獨立於圖形邏輯,示範單一職責原則。
  • client.cs:主程式進入點,整合上述命名空間,處理遊戲流程、分數計算、例外處理(輸入非數字預設押注 100)、多型呼叫 sp.Draw() 與 sp.GetArea()。

關鍵技術點解析

1. 命名空間與 DLL 切割

// MyShape.cs
namespace MyShape {
    public class Shape { ... }
    public class Rectangle : Shape { ... }
    public class Square : Rectangle { ... }
}

將相關類別歸入同一命名空間 MyShape,編譯為 MyShape.dll;訊息類別獨立為 MyMessage.dll。主程式透過 using MyShape; using MyMessage; 導入,達到模組化與重複使用。

2. 繼承、覆寫與多型

public class Shape {
    public virtual void Draw() { }
    public virtual int GetArea() { return 0; }
}
public class Rectangle : Shape {
    public override int GetArea() { return a * b; }
    public override void Draw() { /* 繪製矩形 */ }
}
public class Square : Rectangle {
    public Square(int va) : base(va, va) { }
    public override void Draw() { /* 繪製正方形 */ }
}
  • virtual 允許衍生類別覆寫。
  • override 實現執行期繫結,主程式宣告 Shape sp 卻能呼叫實際物件的 Draw() 與 GetArea(),即為多型。
  • Square 繼承 Rectangle 並透過 base(va, va) 呼叫基底建構函式,展現建構函式鏈結。

3. 例外處理與防呆


try {
    bet = int.Parse(s);
} catch {
    bet = 100; // 輸入非數字預設押注 100
}
if (bet < score) score -= bet;
else { bet = score; score = 0; }

使用 try-catch 捕捉格式錯誤,避免程式當機;並檢查押注不得超過剩餘分數。

4. 編譯指令


csc /target:library /out:MyShape.dll MyShape.cs rect.cs triangle.cs
csc /target:library /out:MyMessage.dll MyMessage.cs
csc /reference:MyShape.dll;MyMessage.dll client.cs
  • /target:library 產出 DLL。
  • /reference 讓主程式參考兩個 DLL。

完整程式碼

// MyShape.cs
using System;
namespace MyShape {
    public class Shape {
        public virtual void Draw() { }
        public virtual int GetArea() { return 0; }
    }
}

// rect.cs
using System;
namespace MyShape {
    public class Rectangle : Shape {
        protected int a, b;
        public Rectangle(int va, int vb) { a = va; b = vb; }
        public override int GetArea() { return a * b; }
        public override void Draw() {
            Console.WriteLine("Rectangle:");
            Console.WriteLine("* * * * *");
            Console.WriteLine("*       *");
            Console.WriteLine("*       *");
            Console.WriteLine("* * * * *");
        }
    }
    public class Square : Rectangle {
        public Square(int va) : base(va, va) { }
        public override void Draw() {
            Console.WriteLine("Square");
            Console.WriteLine("* * * * *");
            Console.WriteLine("*       *");
            Console.WriteLine("*       *");
            Console.WriteLine("*       *");
            Console.WriteLine("* * * * *");
        }
    }
}

// triangle.cs
using System;
namespace MyShape {
    public class Triangle : Shape {
        protected int a, b, c;
        public Triangle(int va, int vb, int vc) { a = va; b = vb; c = vc; }
        public override int GetArea() {
            int s = (a + b + c) / 2;
            return (int)Math.Sqrt(s * (s - a) * (s - b) * (s - c));
        }
    }
    public class RectTriangle : Triangle {
        new protected int a, b;
        public RectTriangle(int va, int vb) : base(va, vb, (int)Math.Sqrt(va * va + vb * vb)) {
            a = va; b = vb;
        }
        public override int GetArea() { return a * b / 2; }
        public override void Draw() {
            Console.WriteLine("RectTriangle");
            Console.WriteLine("*");
            Console.WriteLine("* *");
            Console.WriteLine("*   *");
            Console.WriteLine("* * * *");
        }
    }
    public class RectEqualTriangle : RectTriangle {
        new protected int a;
        public RectEqualTriangle(int va) : base(va, va) { a = va; }
        public override int GetArea() { return a * a / 2; }
        public override void Draw() {
            Console.WriteLine("RectEqualTriangle");
            Console.WriteLine("*");
            Console.WriteLine("* *");
            Console.WriteLine("*   *");
            Console.WriteLine("*     *");
            Console.WriteLine("* * * * *");
        }
    }
}

// Mymessage.cs
using System;
namespace MyMessage {
    public class Message {
        public void Begin() {
            Console.WriteLine("******************************");
            Console.WriteLine("*       SHAPE GAME           *");
            Console.WriteLine("******************************");
        }
        public bool Ask() {
            Console.WriteLine("Press 0 to exit, any other key to continue");
            return Console.Read() != '0';
        }
    }
}

// client.cs
using System;
using MyShape;
using MyMessage;
class ClientTest {
    public static void Main() {
        int score = 1000, win, choice, bet;
        string s;
        Shape sp = new Shape();
        Random ran = new Random();
        Message msg = new Message();
        msg.Begin();
        while (true) {
            if (!msg.Ask()) break;
            Console.WriteLine("Your Score: {0}", score);
            Console.WriteLine("Enter your bet:");
            s = Console.ReadLine();
            try { bet = int.Parse(s); } catch { bet = 100; }
            if (bet < score) score -= bet;
            else { bet = score; score = 0; }
            Console.WriteLine("Remain Score: {0}", score);
            win = 0;
            for (int i = 0; i < 3; i++) {
                choice = ran.Next() % 4;
                switch (choice) {
                    case 0: sp = new RectTriangle(5, 4); break;
                    case 1: sp = new RectEqualTriangle(5); break;
                    case 2: sp = new Rectangle(5, 4); break;
                    case 3: sp = new Square(5); break;
                }
                sp.Draw();
                win += sp.GetArea() * (i + 1) * bet / 100;
                Console.WriteLine("Your win: {0}", win);
            }
            score += win;
            Console.WriteLine("Your Score: {0}", score);
            if (score < 100) {
                Console.WriteLine("Score too low to continue.");
                break;
            }
        }
    }
}

總結

此範例完整展示了 C# 專案模組化的實務做法:以命名空間劃分邊界、將功能編譯為獨立 DLL、主程式參考 DLL、善用繼承與多型簡化主流程、例外處理提升健壯性。讀者可嘗試擴充新圖形、加入記分板或圖形化介面,進一步體會架構組織的彈性與維護優勢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved