Interface inheritance/hierarchies in .Net - is there a better way? - c#

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.

Related

Can you create a Finite State Machine using SOLID principles

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.

Access to the variable between multiple scripts for loose coupling in Unity3D

For instance, assume we have a health variable in one script and want to access to this variable in UI script for showing health and on the other hand change pitch of sound according to amount of health.
I know some ways to access this variable but they highly dependent scripts to each other. Like GetComponent, Singelton or even C# event.
I want to know is there any patterns to decrease these dependencies ? (Also efficient and performant)
Edit:
This event system is in my mind but I think It has some dependencies which they can be removed but I don't know how and also I'm not sure about it and its performance.
public class Player {
public class HealthEventArgs : EventArgs {
public int currentHealth;
public HealthChangedEventArgs(int currentHealth) {
this.currentHealth = currentHealth;
}
}
public static event EventHandler<HealthEventArgs> HealthEvent;
public void NotifyHealthChanged(int health) {
if(HealthEvent != null) {
HealthEvent.Invoke(this, new HealthEventArgs(health));
}
}
}
public class OtherClass {
public void SubscribeToPlayerHealthEvent() {
Player.HealthEvent += Foo;
}
public void UnsubscribeFromPlayerHealthEvent() {
Player.HealthEvent -= Foo;
}
public void Foo(object o, HealthEventArgs e) {
//Do something with e.currentHealth
}
}
after # julxzs and i were talking...
did a little checking on best practices... i found this
link
so it turns out singleton is the way to go, check out the page, lots of good info! thx #julxzs
Take a look at dependency injection technique.
I can advice to start with Zenject.

How should you initialize constant data that needs parameters from another part of the code?

I don't think I explained my question very well in the title, so I'll do my best to do it here.
I have an abstract class called Song, a class that extends it MidiSongand then I have a SongCreator interface and a MidiSongCreatorclass that implements it. I would like to have a way to store lots of SongCreators so I can call their Create method but the problem is, since the SongCreators will each be a MidiSongCreator I am wondering how I should initialize each MidiSongCreator since it takes a MIDIPlayer and other things to help initialize it which doesn't have a static reference to it. Should I create a static class that holds lots of SongCreators? Should I not make the SongList class static?
What is looks like:
public abstract class Song{
public IList<Playable> notes { get; private set; }
public SongPlayData Start(){
// calls onStartEvent
return CreateSongData();
}
protected abstract SongPlayData CreateSongData();
public bool Update(SongPlayData songData, float songTime,List<SongPlayer> players) { // note that the players list is a list of people who are playing this game (this is a rhythm game) (doesn't have anything to do with MIDIPlayer
}
public void End(){
//calls end event
}
}
public class MidiSong : Song { // this is the class that needs the MIDIPlayer parameter
public MIDIPlayer midiPlayer;
protected MidiSong(MIDIPlayer player){
this.midiPlayer = player;
}
protected override SongPlayData CreateSongData() {
return new MidiSongData(midiPlayer);
}
}
public interface SongCreator<out T> where T : Song {
T Create();
}
public class MidiSongCreator : SongCreator<MidiSong>, IListenerObject { // this is the class that I need to store lots of instances of. the midiPlayer will probably be the same every time
private MIDIPlayer player;
public MidiSongCreator(MIDIPlayer player) {
this.player = player;
Init();
}
private void Init() {
player.midiListener.listener = this;
//
}
private void Clear() { // resets all the data so we can create another Song if we need to (even without entering stuff in)
if(player.midiListener.listener == this) {
player.midiListener.listener = null;
}
}
public MidiSong Create() {
MidiSong r = new MidiSong(player);
// I'm still going to implement calls to other methods from midiPlayer
Clear();
return r;
}
public void OnLoad(MidiFile file) {
// does stuff to load midi file (deals with individual events)
}
}
public class MasterSong : MonoBehaviour { // this should initialize last btw (It's in the Script Execution Order)
public MIDIPlayer midiPlayer;
public Song song;
public SongPlayData playData;
// Use this for initialization
void Start() {
// this is where I'd like to reference a SongCreator and call it's create method and Start the song
//for instance:
song = SongList.SONG_NAME.Create();
playData = song.Start();
}
void Update() {
}
}
It's a RhythmGame made with unity, but I didn't add the unity tag because I feel that this is more of a C#/design thing.
Also note, that I have my classes much more organized that just one file with all these.
I'm looking for ways to improve on the design that I have.
This is a design problem, domain design!
I suggest don't write code yet. Create a class diagram, with pen and paper, don't need to use tools in the beginning.
Try to determine entities - classes, interfaces etc - and the relationship among them. Just use boxes and arrow, don't need to put details yet. With boxes and arrows, you will be able to have a picture of your domain much more clearly. Keep refining and changing it, still at this high level, without details, until you are satisfied.
Then, step by step, refine it by adding details/properties such attributes and methods. This may cause to change the diagram from the first step.
I intentionally did not refer to specifics of you questions like the classes and interfaces you mentioned. Since, there is not enough information to comment on that. Secondly, and more importantly, you should start at high level of design and once that is done, then do coding based on your design.

Allow all types of generic types in a List

I am having some issues with generics. I have a base-class called Animation, from which different type of animations derive from (e.g double, vector etc etc), and to handle all the animations I use a static class to administrate all the animations basically.
public class Animation<T>
{
public virtual Action<T> UpdateAction { get; set; }
public EasingFunctionBase EasingFunction { get; set; }
private TimeSpan _Duration = TimeSpan.FromMilliseconds(0);
public TimeSpan Duration { get; set; }
public T currentValue { get; internal set; }
internal TimeSpan CurrentTime = TimeSpan.FromMilliseconds(0);
internal double Percentage = 0;
internal bool HasFinished = false;
internal virtual void Update()
{
UpdateAction?.Invoke(CurrentValue);
}
public virtual void BeginAnimation()
{
if (Duration.TotalMilliseconds <= 0)
throw new InvalidOperationException("You need a duration greater than 0 seconds.");
AnimationFactory.BeginAnimation(this);
}
}
DoubleAnimation : Animation<double>
{
*do some calculations and set currentValue*
}
public static class AnimationFactory
{
private static List<Animation> _CurrentAnimations = new List<Animation>();
public static void BeginAnimation<T>(Animation<T> animation)
{
// Here is where I'm getting the error. I want this list to be able to contain all types of Animation<T>.
_CurrentAnimations.Add(animation);
_isEnabled = true;
}
void Update()
{
for(int i = 0; i < _CurrentAnimations.Count; i++)
{
_CurrentAnimations[i].update();
}
}
}
As you can see I am getting an error where I want to add the newly created and to-be-run-animation into the list. How can I make this list accept all kinds of Animation<T>? Or am I going about this wrong? I added the generic type in order to remove casting (if animating structs), but maybe there's a smarter solution.
How can I make this list accept all kinds of Animation?
Unless Animation is a base class of Animation<T>, you can't. What is Animation? What is its relationship to Animation<T>? Based on your additional information, it seems you don't actually have an Animation class, yet.
One alternative would be to make the static class generic as well, e.g. AnimationFactory<T>. Then the list would be List<Animation<T>>. But then you would have a different list for each type parameter T, which doesn't seem like what you are looking for.
Based on the information so far, I would say you should make Animation<T> inherit Animation or some other appropriate base class (using that base class as the type parameter for your List<T>). In this particular example, that would require creating the Animation base class, since that's not actually something that exists yet.
Barring that, your question might be an XY Problem. I.e. you've asked us the wrong question and really should be focused on the broader issue that you're really trying to solve, rather than the nuts and bolts aspect of the list.

Dependency Injection, Class requiring dictionary of same type of interfaces a good idea?

Though I have asked this question in Code Review but the original code is now creeping. Yes, I am also a big fan of Clean code talks just watched those awesome videos, I have also seen this another question. This is the same problem I was originally having.
I have a class say human. Human based on some decision in its Travel method can either call Horse, Camel or Ship To Travel or It can also ask all of them(under some situation) to Travel.
All of the Horse, Camel, Ship have ITransport interface and of course this interface is having Travel method.
initial problem is that it is a possibility that during the life time of my project I may get some new Transportation such as Plane, Rocket, Submarine etc.
So I cannot just Simple pass them in constructor as ITransport ship, ITransport horse..... and so on, as my constructor parameter will keep on swelling.
So I came to a solution as suggested (I think) that HumanFactory should be having an event and that event should be passed in the constructor of Human class.
Although I have somehow removed my large Transportation list, but as You know that interfaces can have lots of methods. So now I will need to pass lots of delegates each corresponding to a method of an interface and ofcourse on a need basis.
I even tried to solve this problem by creating a Human Mapper class whose sole responsibility is to map to right transport, call the right event. This works !
Now, since this is an imaginary example, in real world example the interface's methods accept parameters, so how will I deal with it?
I think the direction in which I am going is creating a Maintenance Nightmare.
I am pasting the code for a quick reference.
interface ITransport
{
void Travel();
}
My Transport Factory is as:
public class TransportFactory
{
....
internal ITransport ProvideTransport(TransportTypes transportType)
{
switch (transportType)
{
case TransportTypes.Camel: return new Camel();
case TransportTypes.Horse: return new Horse();
case TransportTypes.Ship: return new Ship();
default:
return null;
}
}
}
My Human class after suggestion has become as:
public class Human
{
Action<Human, string> _transportRequested;
public Human(Action<Human, string> transportRequested)
{
_transportRequested = transportRequested;
}
public void Travel()
{
if (_transportRequested != null)
{
var ev = _transportRequested;
ev.Invoke(this, GroundTypes.Plains.ToString());
}
}
}
I have a human class factory now as suggested which is as:
public class HumanFactory
{
ITransport camel;
ITransport ship;
ITransport horse;
Human _human;
Dictionary<string, ITransport> _availableTransports;
event Action<Human, string> transportRequested;
public HumanFactory(TransportFactory tFactory)
{
horse = tFactory.ProvideTransport(TransportTypes.Horse);
camel = tFactory.ProvideTransport(TransportTypes.Camel);
ship = tFactory.ProvideTransport(TransportTypes.Ship);
}
public Human ConfigureHuman()
{
if (_availableTransports == null)
{
_availableTransports = new Dictionary<string, ITransport>();
_availableTransports.Add(GroundTypes.Desert.ToString(), camel);
_availableTransports.Add(GroundTypes.Sea.ToString(), ship);
_availableTransports.Add(GroundTypes.Plains.ToString(), horse);
}
transportRequested += new Action<Human, string>(_human_transportRequested);
_human = new Human(transportRequested);
return _human;
}
void _human_transportRequested(Human human, string groundType)
{
if (_availableTransports.ContainsKey(groundType))
{
ITransport suitableTransport = _availableTransports[groundType];
suitableTransport.Travel();
}
else
{
//code for handling below conditions goes here
//I don't know what to do for this type of plain?
}
}
}
I talked about a Mapper class which maps correct transport to correct methods as(it looks ugly but that was the best I came up with :) ):
class Human_Transport_MethodMapper
{
Dictionary<GroundTypes, ITransport> _availableTransports;
List<EventTypes> _availableEvents;
event Action<Human, GroundTypes, EventTypes> transportRequested;
internal Action<Human, GroundTypes, EventTypes> transportRequesteddel;
public Human_Transport_MethodMapper(Dictionary<GroundTypes, ITransport> availableTransports, List<EventTypes> availableEvents)
{
_availableEvents = availableEvents;
_availableTransports = availableTransports;
transportRequested += human_OnAnyEventReceived;
transportRequesteddel = transportRequested;
}
internal void human_OnAnyEventReceived(Human human, GroundTypes groundType, EventTypes eventType)
{
if (_availableTransports.ContainsKey(groundType))
{
ITransport suitableTransport = _availableTransports[groundType];
switch (eventType)
{
case EventTypes.Travel: suitableTransport.Travel();
break;
default:
break; //meaning interface's correct method has not been mapped.
}
}
else
{
//code for handling below conditions goes here
//I don't know what to do for this type of plain?
}
}
}
Now see that in this event, For Travel method if there were two arguments, then delegate signature would had changed, If there were four or five methods in ITransport interface, then may God help me.
I hope I have explained my problem here.
Thanks
Edit: I am removing some obvious code from this question in order to make it more readable and also it is getting more verbose
First of all, the way you deal with standart events is confusing and overcomplicated. You dont need to pass events to constructor See my last edit in previous topic on how it can be simplified.
Also, as i mentioned in previous topic, the common way to deal with complicated event network in large applications is to implement EventsAggregator pattern (http://codebetter.com/jeremymiller/2009/07/22/braindump-on-the-event-aggregator-pattern/). There are zillions of various implenetations availible on the web, so i leave it up to you to pick one. I will use this interface for example purposes:
interface IEventsAggregator
{
//sends message to network
void Publish(object message);
//adds object to the list of handlers
void Subscribe(object listener);
//removes object from the list of handlers
void Unsubscribe(object listener);
}
//listeners should implement this interface
interface IListener<TMessage>
{
//handling logic for particular message
void Handle(TMessgae message);
}
Then your code can be refactored:
//you do not need human factory in this example
public class Human
{
private readonly IEventsAggregator _events;
//see Handle implementation for details
//public ITransport Transport { get; set; }
public Human(IEventsAggregator events)
{
_events = events;
}
public void Travel(GroundTypes type)
{
_events.Publish(new TransportRequest(this, type));
//see Handle implementation for details
//if (Transport != null) Transport.Travel();
}
}
public class TransportRequest
{
public Human Sender { get; set; }
public GroundTypes Ground { get; set; }
public TransportRequest(Human sensder, GroundTypes ground)
{
Sender = sender;
Ground = ground;
}
}
public class TravelAgency : IListener<TransportRequest>, IDisposable
{
private readonly IEventsAggregator _events;
private readonly TransportFactory _tFactory;
public TravelAgency(IEventsAggregator events, TransportFactory tFactory)
{
_events = events;
_events.Subscribe(this);
_tFactory = tFactory;
}
public void Handle(TransportRequest request)
{
var transort = _tFactory.ProvideTransport(...);
//insert the handling logic here
//there are two ways to handle this message:
//1) you give human no control over (and no knowledge of) Transport
//and simply call transport.Travel(request.Sender); here
//2) or you add ITransport property to Human class
//and do only the assignation here
//request.Sender.Transport = transport;
//and then let the human manage Transport object
}
public void Dispose()
{
_events.Unsubscribe(this);
}
}
This is probably how i would do it, if i needed to stricktly separate logic for some reason. It might be a bit too complicated for such trivial task, but i think it is a good basement for larger application. :) There are probably other approaches tho.

Categories