I'm currently studying game development and for one of our projects, we had to create a finite state machine that would function as a simple AI. It has always been encouraged to make your code with SOLID principles but for this project I couldn't think of a way to do it. Although it wasn't required for this project I would still like to find a way to do it. It's made in Unity c#.
public interface IState
{
public IState CheckForState();
}
public class Walk : IState
{
float speed = 10;
public IState CheckForState()
{
if (speed > 5)
{
return Run;
}
return this;
}
}
To make it SOLID you would have to find a way to remove 'Run' from the function cause if the 'Run' script is removed the function wouldn't work anymore, but it should still be able to get it if available.
There's a couple solutions that come to mind that would allow for a fully SOLID solution.
Solution 1
The first and simplest to suffice the dependency inversion principle is to inject the Run class into the Walk class, like so:
public class Walk : IState
{
float speed = 10;
private readonly IState _runState;
public Walk(IState runState)
{
_runState = runState;
}
public IState CheckForState()
{
if (speed > 5)
{
return _runState;
}
return this;
}
}
This solution makes it so Walk is no longer dependent on a concrete implementation of Run, but still allows it to transition to a run state. However, this does require that Walk knows which states it can transition to (which I think is a reasonable expectation).
Solution 2
You can further decouple this by representing the state transitions as objects. This would look something like this:
public interface IState
{
public IState CheckForState();
public float Value {get;}
}
public interface IStateTransition
{
public IState CheckTransition(IState source);
}
public class GreaterThanTransition : IStateTransition
{
private readonly IState _targetState;
private readonly int _checkValue;
public GreaterThanTransition(IState targetState, int checkValue)
{
_targetState = targetState;
_checkValue = checkValue;
}
public IState CheckTransition(IState sourceState) => sourceState.Value > _checkValue ? _targetState : sourceState;
}
public class Walk : IState
{
private readonly List<IStateTransition> _transitions;
public Walk(List<IStateTransition> transitions)
{
_transitions = transitions;
}
public float Value => 10;
public IState CheckForState() => _transitions.Select(t => t.CheckTransition(this)).FirstOrDefault(s => s != this) ?? this;
}
Then you can create a Walk instance like this:
new Walk(new List<IStateTransition>
{
new GreaterThanTransition(new Run(...), 5)
});
This requires that a value from the state object can be used in the IStateTransition to check if a state transition needs to occur. I used an int in my example as the type of the Value property, but you could easily switch it to be a generic type.
This solution completely decouples each state and captures the state transitions as reusable components. It is more complex in some regards since the code is now split across more classes and interfaces, but it also fully incorporates the SOLID principles.
Related
I've been struggling with a small DI problem, that I think should be very easy to solve, but for some reason I can't find the solution.
I have a service that should one one DI object in the same way for two different things.
public class EquationManager : IEquationManager
{
private readonly IEquationEvaluator _equationEvaluator;
private readonly IEquationEvaluator _inversEquationEvaluator;
public EquationManager(IEquationEvaluator equationEvaluator)
{
_equationEvaluator = equationEvaluator;
_inversEquationEvaluator = equationEvaluator;
}
}
So what I would need is 2 instances of the same DI. That's all. If I write the code as it is, they are shallow copies, what ever I set to _inversEquationEvaluator is also updated in _equationEvaluator ( which is normal).
How do I have 2 separate instances of the same DI? Is this possible in a simple way. I would like to avoid registering IEquationEvaluator in 2 different ways in the container.
My second question: is my architecture wrong? What I want to achieve here is having an math equation that takes an input parameter (int) and output a double value. I need now a way to revert this process using an other equation. So I input a double value and in theory I should obtain an int value. IEquationEvaluator is a class that deals with the math operation.
You can use this pattern:
public enum EquationEvaluatorType
{
EquationEvaluator,
InversEquationEvaluator
}
public interface IEquationEvaluator
{
public EquationEvaluatorType Type { get; }
//your methods and properties
}
public class EquationEvaluator : IEquationEvaluator
{
public EquationEvaluatorType Type => EquationEvaluatorType.EquationEvaluator;
}
public class InversEquationEvaluator : IEquationEvaluator
{
public EquationEvaluatorType Type => EquationEvaluatorType.InversEquationEvaluator;
}
public class EquationManager : IEquationManager
{
private readonly IEquationEvaluator _equationEvaluator;
private readonly IEquationEvaluator _inversEquationEvaluator;
public EquationManager(IEnumerable<IEquationEvaluator> items)
{
_equationEvaluator = items.First(x=>x.Type==EquationEvaluatorType.EquationEvaluator);
_inversEquationEvaluator = items.First(x => x.Type == EquationEvaluatorType.InversEquationEvaluator);
}
}
And in your startup:
services.AddScoped<IEquationEvaluator, EquationEvaluator>();
services.AddScoped<IEquationEvaluator, InversEquationEvaluator>();
I have a Unity project with an ever growing amount of "placeholder assets" (such as ScriptableObjects for Items and Enemies). So I was thinking it would be neat if I could somehow; (1) flag them as being placeholders, and also (2) give them an estimated production cost. In order to parse through all of them during build/play-time and output something like this in the log: "Build contains 125 placeholders, at en estimated cost of 3275 USD."
I was hoping this would be as easy as creating an Interface that I could implement on all my various classes which represent assets/content, to give me these extra fields (e.g. bool isPlaceholder and float costEstimate). Like this:
namespace PlaceholderInfo
{
public interface IPlaceholderInfo
{
bool isPlaceholder = false;
float costEstimate = 0f;
}
}
And then end up with something like this in the Inspector, that I could easy edit for all assets:
And later to parse through that data, perhaps using this method https://answers.unity.com/questions/863509/how-can-i-find-all-objects-that-have-a-script-that.html - but I'm currently stuck at the FIRST step, as I just learned (the hard way) that Interfaces can't even have fields! :(
What shall I do? Is there another approach I can take?
You can create the class that inherit IPlaceholderInfo like this:
[Serializable]
public class SomeInfo : IPlaceholderInfo
{
public bool isPlaceholder = false;
public float costEstimate = 0f;
}
And after that just add this info to some MonoBehavior class which inherit some interface like this:
public interface IDataContainer
{
IPlaceholderInfo[] GetInfo();
}
public class JustAnotherContainer : MonoBehavior, IDataContainer
{
[SerializedField] private SomeInfo[] someInfo;
public IPlaceholderInfo[] GetInfo()
{
return someInfo;
}
}
And after that you can find this data like this:
public Start()
{
var data = FindObjectsOfType<MonoBehaviour>().OfType<IDataContainer>();
//or you can use this if you have only 1 object with data
var info = gameObject.GetComponentsInChildren<IDataContainer>();
}
For my project purpose I need to send metrics to AWS.
I have main class called SendingMetrics.
private CPUMetric _cpuMetric;
private RAMMetric _ramMetric;
private HDDMetric _hddMetric;
private CloudWatchClient _cloudWatchClient(); //AWS Client which contains method Send() that sends metrics to AWS
public SendingMetrics()
{
_cpuMetric = new CPUMetric();
_ramMetric = new RAMMetric();
_hddMetric = new HDDMetric();
_cloudwatchClient = new CloudwatchClient();
InitializeTimer();
}
private void InitializeTimer()
{
//here I initialize Timer object which will call method SendMetrics() each 60 seconds.
}
private void SendMetrics()
{
SendCPUMetric();
SendRAMMetric();
SendHDDMetric();
}
private void SendCPUMetric()
{
_cloudwatchClient.Send("CPU_Metric", _cpuMetric.GetValue());
}
private void SendRAMMetric()
{
_cloudwatchClient.Send("RAM_Metric", _ramMetric.GetValue());
}
private void SendHDDMetric()
{
_cloudwatchClient.Send("HDD_Metric", _hddMetric.GetValue());
}
Also I have CPUMetric, RAMMetric and HDDMetric classes that looks pretty much similar so I will just show code of one class.
internal sealed class CPUMetric
{
private int _cpuThreshold;
public CPUMetric()
{
_cpuThreshold = 95;
}
public int GetValue()
{
var currentCpuLoad = ... //logic for getting machine CPU load
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
So the problem I have is that clean coding is not satisfied in my example. I have 3 metrics to send and if I need to introduce new metric I will need to create new class, initialize it in SendingMetrics class and modify that class and that is not what I want. I want to satisfy Open Closed principle, so it is open for extensions but closed for modifications.
What is the right way to do it? I would move those send methods (SendCPUMetric, SendRAMMetric, SendHDDMetric) to corresponding classes (SendCPUMetric method to CPUMetric class, SendRAMMEtric to RAMMetric, etc) but how to modfy SendingMetrics class so it is closed for modifications and if I need to add new metric to not change that class.
In object oriented languages like C# the Open Closed Principle (OCP) is usually achieved by using the concept of polymorphism. That is that objects of the same kind react different to one and the same message. Looking at your class "SendingMetrics" it's obvious that the class works with different types of "Metrics". The good thing is that your class "SendingMetrics" talks to a all types of metrics in the same way by sending the message "getData". Hence you can introduce a new abstraction by creating an Interface "IMetric" that is implemented by the concrete types of metrics. That way you decouple your "SendingMetrics" class from the concrete metric types wich means the class does not know about the specific metric types. It only knows IMetric and treats them all in the same way wich makes it possible to add any new collaborator (type of metric) that implements the IMetric interface (open for extension) without the need to change the "SendingMetrics" class (closed for modification). This also requires that the objects of the different types of metrics are not created within the "SendingMetrics" class but e.g. by a factory or outside of the class and being injected as IMetrics.
In addition to using inheritance to enable polymorphism and achiving OCP by introducing the interface IMetric you can also use inheritance to remove redundancy. Which means you can introduce an abstract base class for all metric types that implements common behaviour that is used by all types of metrics.
Your design is almost correct. You got 3 data retriever and 1 data sender. So it's easy to add more metric (more retriever) (open for extensions) without affecting current metrics (closed for modifications), you just need a bit more refactor to reduce duplicated code.
Instead of have 3 metrics classes look very similar. Only below line is different
var currentCpuLoad = ... //logic for getting machine CPU load
You can create a generic metric like this
internal interface IGetMetric
{
int GetData();
}
internal sealed class Metric
{
private int _threshold;
private IGetMetric _getDataService;
public Metric(IGetMetric getDataService)
{
_cpuThreshold = 95;
_getDataService = getDataService;
}
public int GetValue()
{
var currentCpuLoad = _getDataService.GetData();
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
Then just create 3 GetMetric classes to implement that interface. This is just 1 way to reduce the code duplication. You can also use inheritance (but I don't like inheritance). Or you can use a Func param.
UPDATED: added class to get CPU metric
internal class CPUMetricService : IGetMetric
{
public int GetData() { return ....; }
}
internal class RAMMetricService : IGetMetric
{
public int GetData() { return ....; }
}
public class AllMetrics
{
private List<Metric> _metrics = new List<Metric>()
{
new Metric(new CPUMetricService());
new Metric(new RAMMetricService());
}
public void SendMetrics()
{
_metrics.ForEach(m => ....);
}
}
I am currently writing a software program for a tour, made up of exhibits. The exhibit object, at any given point, is in one of four states, defined by the ExhibitStates enum:
private enum ExhibitState { Ready, Active, Complete, Inactive };
For developers who will be setting up exhibits, there are only two "starting" states that I want them to be able to choose from:
public enum StartingExhibitState { Ready, Inactive };
Currently, I have it set up so that upon being initialized, the exhibit will immediately set its state to match its starting state, like so:
switch (startingState) {
case StartingExhibitState.Ready:
SetState(ExhibitState.Ready);
break;
case StartingExhibitState.Inactive:
SetState(ExhibitState.Inactive);
break;
}
I found myself wondering today if this was the best practice. Is there a better way to restrict which enum options are public and which are private? Or is it best to simply have the two separate enums?
Thank you so much for your time.
If you create second enum - your intents will be very clearly explained through signature of setting method
public enum ExhibitState
{
Inactive = 0,
Active = 1,
Ready = 2,
Complete = 3
};
public enum InitialStates
{
Inactive = ExhibitState.Inactive,
Ready = ExhibitState.Ready
};
public void SetInitial(InitialStates state)
{
SetState((ExhibitState)state);
}
If you go further you can add compiler help for preventing passing wrong values to the method.
public sealed class InitialState
{
public static readonly InitialState Initial = new InitialState(ExhibitState.Initial);
public static readonly InitialState Ready = new InitialState(ExhibitState.Ready);
public ExhibitState State { get; }
private InitialState(ExhibitState state)
{
State = state;
}
}
Constructor made private to prevent instantiating class from else where.
Class marked as sealed to prevent deriving and changing it behaviour.
Then your method will look like
public void SetInitial(InitialState start)
{
SetState(start.State);
}
// use it
SetInitial(InitialState.Initial);
SetInitial(InitialState.Ready);
Nothing else cannot be passed, until you change code of InitialState class.
Instead of using an enum (or two of them), you could use a class-based approach:
public abstract class ExhibitState
{
public static ExhibitInitialState Ready { get { return new ExhibitReadyState(); } }
public static ExhibitInitialState Inactive { get { return new ExhibitInactiveState(); } }
public static ExhibitState Complete { get { return new ExhibitCompleteState(); } }
public static ExhibitState Active { get { return new ExhibitActiveState(); } }
private class ExhibitReadyState : ExhibitInitialState {}
private class ExhibitInactiveState : ExhibitInitialState {}
private class ExhibitCompleteState : ExhibitState {}
private class ExhibitActiveState : ExhibitState {}
}
public abstract class ExhibitInitialState : ExhibitState {}
The above sample shows a simple approach. Usually, you'd not create a new instance of a state in the get methods, but have static instances so that comparing is easier.
Similar to an enum, you could still type ExhibitState.Ready or the other states. In addition, the base class ExhibitInitialState allows you to limit the states that can be set initially:
public void SetInitial(ExhibitInitialState initState) { ... }
In comparison to the approach that #Fabio proposed, you'd have the benefit that you could not mix up the values. Furthermore and especially relevant for states: is very common that the behavior should also change for a specific state. With this class-based approach, you could implement this behavior in the specific ExhibitState implementations and by that avoid lots of switch statements that are likely to exist in an enum-based approach.
I figure I'll use a case study of something in my code as an example of what I mean.
Right now, I'm working on a behavior/action system for my component-based game system. GameObjects can have an IBehaviorComponent and an IActionComponent attached to them, which, showing only the relevant details, expose the following:
public interface IBehaviorComponent : IBaseComponent
{
IBehavior Behavior { get; }
}
public interface IActionComponent : IBaseComponent
{
IAction Action { get; }
void ExecuteAction(IGameObject target = null);
}
Now, this is all fine so far (at least to me!). But, trouble begins to brew when I look at implementations of IActionComponent.
For example, a simple IActionComponent implementation:
public class SimpleActionComponent : IActionComponent
{
public IAction Action { get; protected set; }
public void ExecuteAction(IGameObject target = null)
{
Action.Execute(target);
}
public void Update(float deltaTime) { } //from IBaseComponent
}
But, let's say I want to introduce a more complex IActionComponent implementation that allows for actions to be executed on a timed schedule:
public class TimedActionComponent : IActionComponent
{
public IAction Action { get; protected set; }
public float IdleTime { get; set; }
public float IdleTimeRemaining { get; protected set; }
public void ExecuteAction(IGameObject target = null)
{
IdleTimeRemaining = IdleTime;
}
public void Update(float deltaTime)
{
if (IdleTimeRemaining > 0f)
{
IdleTimeRemaining -= deltaTime;
}
else
{
Action.Execute(target);
}
}
}
And now, let's say I want to expose IdleTime so that it can be changed by outside influences. My thoughts at first were to create a new interface:
public interface ITimedActionComponent : IActionComponent
{
float IdleTime { get; set; }
float IdleTimeRemaining { get; set; }
}
However, the issue here is that my component system stores everything at one-level-up from IBaseComponent. So, the action component for a GameObject is retrieved as an IActionComponent, -not- as, say, an ITimedActionComponent, or an IRandomizedActionComponent, or even an ICrashTheProgramActionComponent. I hope the reasons for this are obvious, as I want anything to be able to query the GameObject for one of it's components without having to know exactly what it wants beyond the basic type of component (IActionComponent, IRenderableComponent, IPhysicsComponent, etc.)
Is there a cleaner way of handling this, that will allow me to expose these properties defined in child classes without everything having to cast the retrieved IActionComponent to the type it's interested in? Or is that simply the only/best way of accomplishing this. Something like:
public void IWantYouToAttackSuperSlow(IGameObject target)
{
//Let's get the action component for the gameobject and test if it's an ITimedActionComponent...
ITimedActionComponent actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent;
if (actionComponent != null) //We're okay!
{
actionComponent.IdleTime = int.MaxValue; //Mwhaha
}
}
Right now I am thinking that's The Only Way, but I figured I'd see if there's a pattern hiding in the woodwork that I'm ignorant of, or if anyone can suggest a much better way of accomplishing this to begin with.
Thanks!
The code you showed that casts-down an IActionComponent to an ITimedActionComponent is (as far as I can see) unavoidable- you have to be aware of the IdleTime properties in order to use them, right?
I think the trick here would be to hide that not-so-nice-looking code where the classes that use your IActionComponent won't have to deal with it.
My first thought on how to do this is to use a Factory:
public void IWantYouToAttackSuperSlow(IGameObject target)
{
//Let's get the action component for the gameobject
IActionComponent actionComponent = ActionComponentsFactory.GetTimedActionComponentIfAvailable(int.MaxValue);
}
and your factory's method:
public IActionComponent GetTimedActionComponentIfAvailable(IGameObject target, int idleTime)
{
var actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent;
if (actionComponent != null) //We're okay!
{
actionComponent.IdleTime = int.MaxValue; //Mwhaha
}
return (actionComponent != null)? actionComponent : target.GetComponent<IActionComponent>();
}
You're right, it's not a good idea to test for a specific implementation by casting to subtypes. From the examples you have provided it looks like you have an IGameObject that you want to perform some action on. Rather than having your IActionComponent expose a method that takes the IGameObject as an argument you could sort of do it the other way around, i.e. let the IGameObject take one, or many if you prefer, actions that you can execute.
interface IActionComponent
{
ExecuteAction();
}
interface IGameObject
{
IActionComponent ActionComponent { get; }
}
then in the executing method do
public void IWantYouToAttackSuperSlow(IGameObject target)
{
target.ActionComponent.ExecuteAction();
}
Depending on how you implement IActionComponent, polymorphism will make sure that the right code is executed.
There is a pattern called Command Pattern that seems to fit your need.