Skip to content

Commit

Permalink
Added factory architecture to assist with creating factories of item …
Browse files Browse the repository at this point in the history
…types. Courtesy of Thraka and the GoRogue-SadConsole integration library for the original code :D
  • Loading branch information
Chris3606 committed Feb 5, 2020
1 parent 8cc280e commit 8ff1867
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 0 deletions.
13 changes: 13 additions & 0 deletions GoRogue/Factory/BlueprintConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SadConsole.Factory
{
/// <summary>
/// Base class for a settings object that contains parameters to pass to the Create function of a factory.
/// </summary>
public class BlueprintConfig
{
/// <summary>
/// Represents no arguments -- pass as the config parameter to Create if there are no parameters you wish to pass.
/// </summary>
public static readonly BlueprintConfig Empty = new BlueprintConfig();
}
}
109 changes: 109 additions & 0 deletions GoRogue/Factory/Factory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace SadConsole.Factory
{
/// <summary>
/// A factory that produces a type of object based on a blueprint and a set of configuration parameters.
/// </summary>
/// <typeparam name="TBlueprintConfig">The type of parameter passed to the <see cref="Create(string, TBlueprintConfig)"/> function each time an object is created.</typeparam>
/// <typeparam name="TProduced">The type of object this factory creates.</typeparam>
public class Factory<TBlueprintConfig, TProduced> : IEnumerable<IBlueprint<TBlueprintConfig, TProduced>>
where TBlueprintConfig : BlueprintConfig
{
private readonly Dictionary<string, IBlueprint<TBlueprintConfig, TProduced>> _blueprints = new Dictionary<string, IBlueprint<TBlueprintConfig, TProduced>>();

/// <summary>
/// Adds a blueprint to the factory.
/// </summary>
/// <param name="blueprint">The blueprint to add.</param>
public void Add(IBlueprint<TBlueprintConfig, TProduced> blueprint) => _blueprints[blueprint.Id] = blueprint;

/// <summary>
/// Creates a <typeparamref name="TProduced"/> object using the blueprint with the given factory id, and the given settings object.
/// </summary>
/// <param name="factoryId">The factory id of a blueprint.</param>
/// <param name="blueprintConfig">A settings object passed to the Create function of the blueprint.</param>
/// <returns>A new object.</returns>
public TProduced Create(string factoryId, TBlueprintConfig blueprintConfig)
{
if (!_blueprints.ContainsKey(factoryId))
{
throw new ItemNotDefinedException(factoryId);
}

TProduced obj = _blueprints[factoryId].Create(blueprintConfig);
if (obj is IFactoryObject factoryObj)
{
factoryObj.DefinitionId = factoryId;
}

return obj;
}

/// <summary>
/// Checks if a blueprint exists.
/// </summary>
/// <param name="factoryId">The blueprint to check for.</param>
/// <returns>Returns true when the specified <paramref name="factoryId"/> exists; otherwise false.</returns>
public bool BlueprintExists(string factoryId) => _blueprints.ContainsKey(factoryId);

/// <summary>
/// Gets a blueprint by identifier.
/// </summary>
/// <param name="factoryId">The blueprint identifier to get.</param>
/// <returns>The blueprint of the object.</returns>
/// <exception cref="ItemNotDefinedException">Thrown if the factory identifier does not exist.</exception>
public IBlueprint<TBlueprintConfig, TProduced> GetBlueprint(string factoryId)
{
if (!_blueprints.ContainsKey(factoryId))
{
throw new ItemNotDefinedException(factoryId);
}

return _blueprints[factoryId];
}

/// <summary>
/// Gets an enumerator of all of the blueprints in the factory.
/// </summary>
/// <returns>An enumeration of the blueprints.</returns>
public IEnumerator<IBlueprint<TBlueprintConfig, TProduced>> GetEnumerator() => _blueprints.Values.GetEnumerator();

/// <summary>
/// Gets an enumerator of all of the blueprints in the factory.
/// </summary>
/// <returns>An enumeration of the blueprints.</returns>
IEnumerator IEnumerable.GetEnumerator() => _blueprints.Values.GetEnumerator();
}

/// <summary>
/// Exception thrown by <see cref="Factory{TBlueprintConfig, TProduced}"/> objects when a blueprint that doesn't exist is used.
/// </summary>
[Serializable]
public class ItemNotDefinedException : Exception
{
/// <summary>
/// Creates an exception.
/// </summary>
/// <param name="factoryId">Factory id that caused the error.</param>
public ItemNotDefinedException(string factoryId)
: base($"The item '{factoryId}' has not been added to this factory.")
{ }
}

/// <summary>
/// A factory that produces a type of object based on a blueprint.
/// </summary>
/// <typeparam name="TProduced">The type of object this factory creates.</typeparam>
public class Factory<TProduced> : Factory<BlueprintConfig, TProduced>
{
/// <summary>
/// Creates a <typeparamref name="TProduced"/> object using the blueprint with the given factory id.
/// </summary>
/// <param name="factoryId">The factory id of a blueprint.</param>
/// <returns>A new object.</returns>
public TProduced Create(string factoryId) => Create(factoryId, BlueprintConfig.Empty);
}
}
22 changes: 22 additions & 0 deletions GoRogue/Factory/IBlueprint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace SadConsole.Factory
{
/// <summary>
/// Defines how to create a <typeparamref name="TProduced"/> object.
/// </summary>
/// <typeparam name="TBlueprintConfig">The type of the parameter to pass to the <see cref="Create(TBlueprintConfig)"/> function.</typeparam>
/// <typeparam name="TProduced">The type of object to create.</typeparam>
public interface IBlueprint<in TBlueprintConfig, out TProduced> where TBlueprintConfig : BlueprintConfig
{
/// <summary>
/// A unique identifier of this factory definition.
/// </summary>
string Id { get; }

/// <summary>
/// Creates a <typeparamref name="TProduced"/> object.
/// </summary>
/// <param name="config">Configuration parameters used to create the object.</param>
/// <returns>The created object.</returns>
TProduced Create(TBlueprintConfig config);
}
}
15 changes: 15 additions & 0 deletions GoRogue/Factory/IFactoryObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace SadConsole.Factory
{
/// <summary>
/// Interface that can optionally be implemented by objects created via a <see cref="Factory{TBlueprintConfig, TProduced}"/>. The <see cref="DefinitionId"/> property
/// will be automatically set to the ID of the blueprint used to create the object when the Factory's Create function is called.
/// </summary>
public interface IFactoryObject
{
/// <summary>
/// The identifier of the <see cref="IBlueprint{TBlueprintConfig, TProduced}"/> that created this object. Do not set manually -- <see cref="Factory{TBlueprintConfig, TProduced}"/>
/// will automatically set this field when the object is created.
/// </summary>
string DefinitionId { get; set; }
}
}
34 changes: 34 additions & 0 deletions GoRogue/Factory/SimpleBlueprint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace SadConsole.Factory
{
/// <summary>
/// A simple <see cref="IBlueprint{TBlueprintConfig, TProduced}"/> that can be used when no configuration object is necessary to create the object.
/// Implements <see cref="IBlueprint{BlueprintConfig, TProduced}"/>.
/// </summary>
/// <typeparam name="TProduced">The type of object to create.</typeparam>
public abstract class SimpleBlueprint<TProduced> : IBlueprint<BlueprintConfig, TProduced>
{
/// <summary>
/// A unique identifier of this factory definition.
/// </summary>
public string Id { get; }

/// <summary>
/// Creates a SimpleBlueprint with the given blueprint id.
/// </summary>
/// <param name="id">ID for the blueprint.</param>
public SimpleBlueprint(string id) => Id = id;

/// <summary>
/// Calls <see cref="Create()"/>.
/// </summary>
/// <param name="config">Unused.</param>
/// <returns>The created object.</returns>
public TProduced Create(BlueprintConfig config) => Create();

/// <summary>
/// Creates a <typeparamref name="TProduced"/> object.
/// </summary>
/// <returns>The created object.</returns>
public abstract TProduced Create();
}
}

0 comments on commit 8ff1867

Please sign in to comment.