-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #312 from Chris3606/develop
GoRogue 3.0.0-beta07
- Loading branch information
Showing
34 changed files
with
885 additions
and
387 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--- | ||
title: Factories | ||
--- | ||
|
||
# Factory Classes | ||
One common paradigm in development is to have a "factory" whose responsibility is to produce objects of a given type. This can be as simple as a class with static methods whose name corresponds to the name of the object it creates; for example, you could have an `EnemyFactory` class which has methods called `Orc()`, `Goblin()`, etc; however implementations which conveniently allow for serialization and/or customization via user-readable data files can become more complex. GoRogue provides a set of pre-built classes which provide one possible way of implementing this paradigm. | ||
|
||
# Factories in Concept | ||
The GoRogue factory implementations consist of two components; the factory class, and blueprints. A blueprint is simply a unique identifier which denotes the type of item it creates, paired with a function which, when called, creates an object of that type. One or more blueprints are added to a factory class. After blueprints have been added, you call the `Create()` function on the factory. This function is passed a type of item as a parameter (eg. the identifier of a blueprint), and will call the appropriate blueprint's `Create()` function in order to create an item of that type and return it to you. | ||
|
||
# Basic Usage | ||
The simplest way to use the factory system, is to create a `Factory` which consists of `LambdaFactoryBlueprint` instances, which allow you to specify the creation function as a `Func<TProduced>`: | ||
|
||
[!code-csharp[](../../../GoRogue.Snippets/HowTos/Factories/Factory.cs#BasicExample)] | ||
|
||
You could also create a subclass of `Factory` and have the creation functions be (static or non-static) methods on that subclass, if you prefer: | ||
|
||
[!code-csharp[](../../../GoRogue.Snippets/HowTos/Factories/Factory.cs#SubclassExample)] | ||
|
||
This may be cleaner than anonymous functions if your creation methods are more complex and entail a fair a bit of code. | ||
|
||
`LambdaFactoryBlueprint` instances work best as your blueprint type when your blueprints have no state or wrapper code associated with them. If you do have some state, have more advanced customization or parameterization you wish to do, or simply prefer creating subclasses for each item type, the blueprint types need only implement `IFactoryBlueprint`; so you may create your own subclass: | ||
|
||
[!code-csharp[](../../../GoRogue.Snippets/HowTos/Factories/Factory.cs#CustomBlueprintExample)] | ||
|
||
In some cases, you may wish to pass some parameters and/or state to the blueprint when the `Create()` method is called, rather than when the blueprint is created. For this, you should use `AdvancedFactory` instead of `Factory`. `AdvancedFactory` is identical to `Factory` except that it lets you specify an additional type parameter which is the type of a parameter you pass to the factory's `Create` function. This parameter is, in turn, passed to the blueprint. | ||
|
||
Below is an example which aims to pass a Point to the `Create()` function which specifies the object's initial position: | ||
|
||
[!code-csharp[](../../../GoRogue.Snippets/HowTos/Factories/AdvancedFactory.cs#AdvancedFactoryExample)] | ||
|
||
You may also implement an `AdvancedFactory` subclass if you wish, or create custom blueprints by implementing the `IAdvancedFactoryBlueprint` interface yourself, just like the above examples which use `Factory` do. |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\GoRogue\GoRogue.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using GoRogue.DiceNotation; | ||
// ReSharper disable UnusedVariable | ||
|
||
namespace GoRogue.Snippets.HowTos; | ||
public static class DiceNotation | ||
{ | ||
public static void ExampleCode() | ||
{ | ||
#region BasicRolling | ||
int attackRoll = Dice.Roll("1d20+2"); | ||
#endregion | ||
|
||
#region DiceExpression | ||
DiceExpression expr = Dice.Parse("1d12+3"); | ||
|
||
// Returns the minimum possible value for the expression (4) | ||
int minVal = expr.MinRoll(); | ||
|
||
// Returns the maximum possible value for the expression (15) | ||
int maxVal = expr.MaxRoll(); | ||
|
||
// Rolls the expression. Can be called many times on the same DiceExpression | ||
int roll = expr.Roll(); | ||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using GoRogue.Factories; | ||
using SadRogue.Primitives; | ||
// ReSharper disable NotAccessedPositionalProperty.Local | ||
// ReSharper disable UnusedVariable | ||
|
||
namespace GoRogue.Snippets.HowTos.Factories; | ||
|
||
#region AdvancedFactoryExample | ||
public static class AdvancedFactoryExample | ||
{ | ||
record Terrain(Point Position, int Glyph, bool IsWalkable, bool IsTransparent) | ||
: IFactoryObject<string> | ||
{ | ||
public string DefinitionID { get; set; } = ""; | ||
} | ||
|
||
public static void ExampleCode() | ||
{ | ||
// LambdaAdvancedFactoryBlueprint is the same as LambdaFactoryBlueprint but | ||
// implements IAdvancedFactoryBlueprint instead, which allows its creation | ||
// function to take parameters. This is useful, for example, to create objects | ||
// that require parameters to be passed to their constructor. | ||
var factory = new AdvancedFactory<string, Point, Terrain> | ||
{ | ||
new LambdaAdvancedFactoryBlueprint<string, Point, Terrain>( | ||
"Floor", | ||
pos => new Terrain(pos, '.', true, true)), | ||
new LambdaAdvancedFactoryBlueprint<string, Point, Terrain>( | ||
"Wall", | ||
pos => new Terrain(pos, '#', false, false)) | ||
}; | ||
|
||
var floorTile = factory.Create("Floor", new Point(1, 2)); | ||
var wallTile = factory.Create("Wall", new Point(3, 4)); | ||
} | ||
} | ||
#endregion |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
using GoRogue.Factories; | ||
// ReSharper disable NotAccessedPositionalProperty.Local | ||
// ReSharper disable UnusedVariable | ||
|
||
namespace GoRogue.Snippets.HowTos.Factories; | ||
|
||
#region BasicExample | ||
public static class BasicExample | ||
{ | ||
// Arbitrary class we want to create instances of. Implementing the IFactoryObject | ||
// interface is optional, however when we do the DefinitionID field will automatically | ||
// be set to the ID of the blueprint used to create it when a factory's Create method | ||
// is called. | ||
record Terrain(int Glyph, bool IsWalkable, bool IsTransparent) : IFactoryObject<string> | ||
{ | ||
public string DefinitionID { get; set; } = ""; | ||
} | ||
|
||
public static void ExampleCode() | ||
{ | ||
// We'll identify the blueprints with strings in this instance, but this could be | ||
// an enum or any hashable type | ||
var factory = new Factory<string, Terrain>() | ||
{ | ||
new LambdaFactoryBlueprint<string, Terrain>( | ||
"Floor", | ||
()=> new Terrain('.', true, true)), | ||
new LambdaFactoryBlueprint<string, Terrain>( | ||
"Wall", | ||
() => new Terrain('#', false, false)) | ||
}; | ||
|
||
var floorTile = factory.Create("Floor"); | ||
var wallTile = factory.Create("Wall"); | ||
} | ||
} | ||
#endregion | ||
|
||
#region SubclassExample | ||
public static class SubclassExample | ||
{ | ||
record Terrain(int Glyph, bool IsWalkable, bool IsTransparent) : IFactoryObject<string> | ||
{ | ||
public string DefinitionID { get; set; } = ""; | ||
} | ||
|
||
class MyFactory : Factory<string, Terrain> | ||
{ | ||
public MyFactory() | ||
{ | ||
Add(new LambdaFactoryBlueprint<string, Terrain>("Floor", Floor)); | ||
Add(new LambdaFactoryBlueprint<string, Terrain>("Wall", Wall)); | ||
} | ||
|
||
private Terrain Floor() => new('.', true, true); | ||
private Terrain Wall() => new('#', false, false); | ||
} | ||
|
||
public static void ExampleCode() | ||
{ | ||
var factory = new MyFactory(); | ||
|
||
var floorTile = factory.Create("Floor"); | ||
var wallTile = factory.Create("Wall"); | ||
} | ||
|
||
} | ||
#endregion | ||
|
||
#region CustomBlueprintExample | ||
|
||
public static class CustomBlueprintExample | ||
{ | ||
record Terrain(int Glyph, bool IsWalkable, bool IsTransparent) : IFactoryObject<string> | ||
{ | ||
public string DefinitionID { get; set; } = ""; | ||
} | ||
|
||
// A blueprint for terrain which counts the number of times each item type is | ||
// instantiated. | ||
record TerrainBlueprint(string ID, int Glyph, bool IsWalkable, bool IsTransparent) | ||
: IFactoryBlueprint<string, Terrain> | ||
{ | ||
private static readonly Dictionary<string, int> s_countingDictionary = new(); | ||
|
||
public Terrain Create() | ||
{ | ||
s_countingDictionary[ID] = s_countingDictionary.GetValueOrDefault(ID, 0) + 1; | ||
return new Terrain(Glyph, IsWalkable, IsTransparent); | ||
} | ||
} | ||
|
||
public static void ExampleCode() | ||
{ | ||
var factory = new Factory<string, Terrain>() | ||
{ | ||
new TerrainBlueprint( | ||
"Floor", '.', true, true), | ||
new TerrainBlueprint( | ||
"Wall", '#', false, false) | ||
}; | ||
|
||
var floorTile = factory.Create("Floor"); | ||
var wallTile = factory.Create("Wall"); | ||
} | ||
} | ||
#endregion |
Oops, something went wrong.