意圖
用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。
場景
游戲場景中的有很多相似的敵人,它們的技能都一樣,但是隨著敵人出現的位置不同,這些人的能力不太一樣。假設,我們現在需要把三個步兵組成一隊,其中還有一個精英步兵,能力特別高。那麼,你或許可以創建一個敵人抽象類,然後對於不同能力的步兵創建不同的子類。然後,使用工廠方法等設計模式讓調用方依賴敵人抽象類。
問題來了,如果有無數種能力不同步兵,難道需要創建無數子類嗎?還有,步兵模型的初始化工作是非常耗時的,創建這麼多步兵對象可能還會浪費很多時間。我們是不是可以通過只創建一個步兵原型,然後復制出多個一摸一樣的步兵呢?復制後,只需要調整一下這些對象在地圖上出現的位置,或者調整一下它們的能力即可。原型模式就是用來解決這個問題的。
示例代碼
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)
{
List<Enemy> enemyGroup = 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;
enemyGroup.Add(e1);
enemyGroup.Add(e2);
enemyGroup.Add(elite);
return enemyGroup;
}
}
[Serializable]
class Location
{
public int x;
public int y;
public Location(int x, int y)
{
this.x = x;
this.y = y;
}
}
[Serializable]
abstract class Enemy
{
protected Location location;
public Location Location
{
get { return location; }
set { location = value; }
}
protected int power;
public int Power
{
get { return power; }
set { power = value; }
}
protected int speed;
public int Speed
{
get { return 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); // Construct method is assumed to be a high calc work.
this.power = power;
this.speed = speed;
this.location = location;
}
}
[Serializable]
class FootMan : Enemy
{
private string model ;
public FootMan(int power, int speed, Location location)
: base(power, speed, location)
{
model = "footman";
}
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 footman;
if (isDeepCopy)
{
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, this);
memoryStream.Position = 0;
footman = (FootMan)formatter.Deserialize(memoryStream);
}
else
footman = (FootMan)this.MemberwiseClone();
return footman;
}
public void FootmanAttack()
{
Console.WriteLine("FootmanAttack");
}
}
}