Updating Data in your model directly from a class

Viewed 85

I'm making a simple game as a practice project based around random events, to make it easier to add new events I’ve decided to use a keyword system where each event gets keywords assigned to them that are then used to process the event, this can be as simple as displaying as message, changing data in the model or rolling again on the random table.

I have a class that randomly decides an event and returns a List of strings with keywords.

I want to make a class where all the keywords are stored as methods that can then be called with the list.

Something like this:

class Keyword
{
    public void InputKeywords(List<string> Ikeywords)
    {
        foreach (var item in Ikeywords)
        {
            switch (item)
            {
                case "keyword0":
                    keyword0();
                    break;
                case "keyword1":
                    keyword0();
                    break;
                case "keyword2":
                    keyword0();
                    break;
            }
        }
    }

    private void keyword0()
    {
        //do something
    }

    private void keyword1()
    {
        //do something
    }

    private void keyword2()
    {
        //do something
    }
}

Now the problem I’m facing is updating the data in the model from the keywords class. Because the events are chosen at random I don't know for each event what data to send to the class to have it update it.

The solutions I've come up with myself:

  • Make my model static, no more issues with accessing data, Google tells me this is frowned upon and should be avoided.
  • Send the model to the Keyword class, do some magic, and return the model. Would be an easy solution but feels wrong to me, from what I've come to understand about MVVM is that the data should be updated from the viewmodel, but I could be thinking too much inside of the box.
  • Gather all possible data to be changed into a seperate class, send that to the keyword class and update the model afterwards. This sounds like a hassle and feels like I'm just moving the problem elsewhere.

I feel like I'm missing the "right" way of doing this. What would be the "best" approach?

1 Answers

First of all the naming of the keyword class feels misleading here. It is basically an event handler, so I would also name it like on (e.g. RandomEventGenerator)

To your problem I would also not recommend you to use static models. Your testability will suffer from it since you won't use dependency injection there. This being said your second approach seems to go into the right direction. I would suggest to use inject an EventInvoker Interface.

public interface IEventInvoker
{
    public void RaiseEvent();
}

This can be implemented in an operator, which has access to your data model and has predefined actions to modify your data.

public class WeatherOperator : IEventInvoker
{
    private readonly WeatherEngine _weatherEngine;

    public WeatherOperator(WeatherEngine weatherEngine)
    {
        _weatherEngine = weatherEngine;
    }
    public void RaiseEvent()
    {
        StartSunshine();
    }

    public void StartSunshine()
    {
        _weatherEngine.RemoveClouds();
        _weatherEngine.SetSunPosition(DayTimes.Noon);
    }

    public void LetItRain()
    {
        _weatherEngine.SetCloudes(CloudModes.FullCover);
        _weatherEngine.SetRain(RainIntesity.Medium);
    }
}

With a list of the IEventInvoker you can then go to your EventHandler.

public class RandomEventGenerator
{
    private readonly List<IEventInvoker> _eventInvoker;
    private readonly Dictionary<string, Action> _eventDictionary;

    public RandomEventGenerator(List<IEventInvoker> eventOperator, List<string> keywords)
    {
        _eventInvoker = eventOperator;
        _eventDictionary = RegisterKeywordsToRandomEvents(keywords);
    }

    private Dictionary<string,Action> RegisterKeywordsToRandomEvents(List<string> keywords)
    {
        var eventDictionary = new Dictionary<string, Action>();
        foreach (var keyword in keywords)
        {
            var random = new Random();
            var index = random.Next(_eventInvoker.Count);
            eventDictionary.Add(keyword,_eventInvoker[index].RaiseEvent);
        }

        return eventDictionary;
    }

    public void EventByKeyword(string Keyword)
    {
        _eventDictionary[Keyword].Invoke();
    }

    public void RandomEvent()
    {
        var random = new Random();
        var index = random.Next(_eventInvoker.Count);
        _eventInvoker[index].RaiseEvent();
    }
}

Please note that I, to keep it small, didn't used null checks or input validations here, which is highly recommended. With this approach you have a clear cut bettween your model/data and your viewmodel/data accesor.

Related