C# Language
Implementering av Flyweight Design Mönster
Sök…
Implementeringskarta i RPG-spel
Flyweight är ett av konstruktionsmönster. Det används för att minska mängden använt minne genom att dela så mycket data som möjligt med liknande objekt. Detta dokument kommer att lära dig hur du använder Flyweight DP på rätt sätt.
Låt mig förklara idén med det på ett enkelt exempel. Föreställ dig att du arbetar med ett RPG-spel och du måste ladda enorma filer som innehåller några tecken. Till exempel:
-
#
är gräs. Du kan gå på den. -
$
är utgångspunkt -
@
är rock. Du kan inte gå på det. -
%
är skattkista
Exempel på en karta:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@############@@@@@######@#$@@@
@#############@@@######@###@@@
@#######%######@###########@@@
@############################@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Eftersom dessa objekt har liknande egenskaper behöver du inte skapa separata objekt för varje kartfält. Jag ska visa dig hur du använder flygvikt.
Låt oss definiera ett gränssnitt som våra fält kommer att implementera:
public interface IField
{
string Name { get; }
char Mark { get; }
bool CanWalk { get; }
FieldType Type { get; }
}
Nu kan vi skapa klasser som representerar våra fält. Vi måste också identifiera dem på något sätt (jag använde en uppräkning):
public enum FieldType
{
GRASS,
ROCK,
START,
CHEST
}
public class Grass : IField
{
public string Name { get { return "Grass"; } }
public char Mark { get { return '#'; } }
public bool CanWalk { get { return true; } }
public FieldType Type { get { return FieldType.GRASS; } }
}
public class StartingPoint : IField
{
public string Name { get { return "Starting Point"; } }
public char Mark { get { return '$'; } }
public bool CanWalk { get { return true; } }
public FieldType Type { get { return FieldType.START; } }
}
public class Rock : IField
{
public string Name { get { return "Rock"; } }
public char Mark { get { return '@'; } }
public bool CanWalk { get { return false; } }
public FieldType Type { get { return FieldType.ROCK; } }
}
public class TreasureChest : IField
{
public string Name { get { return "Treasure Chest"; } }
public char Mark { get { return '%'; } }
public bool CanWalk { get { return true; } } // you can approach it
public FieldType Type { get { return FieldType.CHEST; } }
}
Som jag sa behöver vi inte skapa en separat instans för varje fält. Vi måste skapa ett arkiv av fält. Kärnan i Flyweight DP är att vi dynamiskt skapar ett objekt endast om vi behöver det och det inte finns ännu i vår repo, eller returnerar det om det redan finns. Låt oss skriva en enkel klass som hanterar detta för oss:
public class FieldRepository
{
private List<IField> lstFields = new List<IField>();
private IField AddField(FieldType type)
{
IField f;
switch(type)
{
case FieldType.GRASS: f = new Grass(); break;
case FieldType.ROCK: f = new Rock(); break;
case FieldType.START: f = new StartingPoint(); break;
case FieldType.CHEST:
default: f = new TreasureChest(); break;
}
lstFields.Add(f); //add it to repository
Console.WriteLine("Created new instance of {0}", f.Name);
return f;
}
public IField GetField(FieldType type)
{
IField f = lstFields.Find(x => x.Type == type);
if (f != null) return f;
else return AddField(type);
}
}
Bra! Nu kan vi testa vår kod:
public class Program
{
public static void Main(string[] args)
{
FieldRepository f = new FieldRepository();
IField grass = f.GetField(FieldType.GRASS);
grass = f.GetField(FieldType.ROCK);
grass = f.GetField(FieldType.GRASS);
}
}
Resultatet i konsolen ska vara:
Skapade en ny instans av Grass
Skapade en ny instans av Rock
Men varför gräs visas bara en gång om vi ville få det två gånger? Det beror på att första gången vi kallar GetField
inte finns i vårt förvar , så det är skapat, men nästa gång vi behöver gräs finns det redan, så vi returnerar det bara.