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

C# 設計模式無廢話系列(五):Prototype 原型模式

     編輯:關於C#

意圖

用原型實例指定創建對象種類,透過拷貝原型創建新對象。

適用場景

遊戲場景大量相似敵人:技能相同,位置不同導致能力微調。需組 3 步兵 + 1 精英步兵。若為每種能力建子類 → 子類爆炸;且步兵模型初始化極耗時。只建一個原型,複製後微調位置/能力 → Prototype 模式。

完整範例程式碼

using System;
using System.Threading;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;

namespace PrototypeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Enemy enemyPrototype = new FootMan(5, 4, new Location(100, 200));
            GameScene gs = new GameScene();
            List<Enemy> enemyGroup = gs.CreateEnemyGroup(enemyPrototype);
            foreach (FootMan ft in enemyGroup)
            {
                ft.ShowInfo();
                ft.FootmanAttack();
            }
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }
    class GameScene
    {
        public List<Enemy> CreateEnemyGroup(Enemy enemyPrototype)
        {
            var group = new List<Enemy>();
            Enemy e1 = enemyPrototype.Clone(true);
            e1.Location.x = enemyPrototype.Location.x - 10;
            Enemy e2 = enemyPrototype.Clone(true);
            e2.Location.x = enemyPrototype.Location.x + 10;
            Enemy elite = enemyPrototype.Clone(true);
            elite.Power = enemyPrototype.Power * 2;
            elite.Speed = enemyPrototype.Speed * 2;
            elite.Location.x = enemyPrototype.Location.x;
            elite.Location.y = enemyPrototype.Location.y + 10;
            group.Add(e1); group.Add(e2); group.Add(elite);
            return group;
        }
    }
    [Serializable]
    class Location { public int x, y; public Location(int x, int y) { this.x = x; this.y = y; } }
    [Serializable]
    abstract class Enemy
    {
        protected Location location;
        public Location Location { get => location; set => location = value; }
        protected int power;
        public int Power { get => power; set => power = value; }
        protected int speed;
        public int Speed { get => speed; set => speed = value; }
        public abstract Enemy Clone(bool isDeepCopy);
        public abstract void ShowInfo();
        public Enemy(int power, int speed, Location location)
        {
            Thread.Sleep(1000); // 模擬高耗時初始化
            this.power = power; this.speed = speed; this.location = location;
        }
    }
    [Serializable]
    class FootMan : Enemy
    {
        string model = "footman";
        public FootMan(int power, int speed, Location location) : base(power, speed, location) { }
        public override void ShowInfo() => Console.WriteLine($"model:{{0}} power:{{1}} speed:{{2}} location:({{3}},{{4}})", model, power, speed, location.x, location.y);
        public override Enemy Clone(bool isDeepCopy)
        {
            FootMan fm;
            if (isDeepCopy)
            {
                using (var ms = new MemoryStream())
                {
                    var bf = new BinaryFormatter();
                    bf.Serialize(ms, this);
                    ms.Position = 0;
                    fm = (FootMan)bf.Deserialize(ms);
                }
            }
            else fm = (FootMan)MemberwiseClone();
            return fm;
        }
        public void FootmanAttack() => Console.WriteLine("FootmanAttack");
    }
}

程式碼執行結果

Prototype 模式執行結果

程式碼解析

  • Enemy:抽象原型,定義屬性(位置/攻擊/速度)、ShowInfo、抽象 Clone。
  • FootMan:具體原型,實作參數與克隆。Clone(bool) 參數決定深/淺拷貝:true 用序列化反序列化深拷貝(含引用類型完整複製),false 用 MemberwiseClone 淺拷貝。
  • GameScene:調用方,零依賴具體類,透過複製原型並微調生成敵人小隊。
  • Prototype 以克隆替代無數子類,減少調用方對具體類依賴。
  • 深拷貝必要性:3 敵人共享同一 Location 實例則位置無法分離,故須深拷貝確保獨立。
  • 建構子 Thread.Sleep(1000) 模擬耗時初始化;克隆僅耗 1 次初始化時間,體現效能優勢。
  • 執行結果:創建 3 敵人總耗時約 1 秒(而非 3 秒),且位置修改互不影響。

何時採用

  • 代碼角度:運行時指定具體類、避免耗時初始化、避免 Factory Method 實現多態。
  • 應用角度:對象多變化多等級、創建極耗時(計算/網路/資料庫)、想獨立創建細節。

實作要點

  • .NET:MemberwiseClone 淺拷貝、序列化反序列化深拷貝(代價較大),視情況選擇。
  • 同需抽象與具體類型,透過穩定抽象減少客戶端修改。
  • 抽象層次可調整:Enemy 為高層抽象;亦可 FootMan 為抽象、下有普通/手榴彈步兵;Tank 為抽象… 只要對象類型由原型指定、新對象由原型拷貝即為 Prototype。

注意事項

  • 謹慎選擇深/淺拷貝。
  • 拷貝並修改意味著原型需公開更多數據,現有系統導入 Prototype 修改成本可能較大。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved