views:

75

answers:

5

I'm cutting my teeth on events and delegates today and to do so, I have been toying with the idea of experience bars, those progress bars from games. But I have a question about the better way to solve my problem - it could be as simple as bad design. Let me provide you some details.

I have modelled my idea with an ExperienceBar class.

It contains properties:

  • int StartValue
  • int CurrentValue
  • int EndValue

and a method

  • void UpdateBar(int)

UpdateBar adds the parameter to CurrentValue and then tests to see if it has reached EndValue. If it exceeds the amount, the EndValue increases and the amount continues on. Note that initially in my thinking, it is not concerned with the effects of reaching the maximum amount possible, just that the end value increases and the StartValue is reset to zero.

Another class called Player has a property of class ExperienceBar.

In my little demo, when Player.ExperienceBar.UpdateBar(int) reaches the EndValue it fires an event which is handled by the Player class. It updates the Player.Level property by one.

I've just realised that I could achieve the same thing by just changing UpdateBar(int) to return type "true". This method could be tested by the Player class and when true, Player.Level increases by one.

So my question - which is the best practice way to handle this rather specific circumstance? As a general rule of thumb for these kind of situations, is it better to handle events, or is it better just to keep it simple with the testing of return statements?

PS: I hope I've made this clear as possible, but I can try to clarify if anyone is having trouble. I believe there may be some redundancies already with my idea, but try not to deviate from the question please. I'm kind of aware of them! Thank you :)

+5  A: 

Well... To me, events is the good way to do it.

However, if I was to design the application it would be down to one question: Will the ExperienceBars's event when it reaches EndValue ever be used by anyone else than the class calling UpdateBar.

If you are designing a component to be used in many places (which seems to be the goal), the answer to me seems to be an almost certain yes, therefore my answer is use events!

/Victor

Victor
+1  A: 

I would use events rather than a return value. Why? Two reasons:

  1. What does returning true mean when returning from UpdateBar? That it was updated? That xyz happened? Someone else looking at this (or you, two months down the road) will wonder as well.
  2. What if more than one thing should occur when the limit is reached? Then you have to tie all of the code related to those things (levelling, getting a new item, whatever) into the method that you used to update the bar in the first place.

I would have an event associated with reaching a certain level and then "listeners" for that event that can respond accordingly.

Michael Todd
I agree with point one, it does add a level of understanding to the code, but then some might argue that good commenting practices would also achieve a similar understanding.
Andrew Weir
+2  A: 

In my opinion, there's no best way to do this. There are various ways to implement the class that, depending on how it is going to be used, are a better or worse fit.

Use events when you want to implement the observer pattern for many "clients" or "observers" who need to know the state of an object and need to be alerted when that state changes. this works for the degenerate case where there is only one client, but the caller of the the method that changes the object's state is not the one that needs to know about the change.

Use return values when the state only needs to be known by the caller, there are no other observers of the class. This is simple, and limits the scope of the knowledge of the state of the class to the item that immediately needs to know it.

And finally, do not over-design this. If it only needs to notify the caller, do not implement events. If at some later date the class needs to be "observed" then implement events at that point.

Oplopanax
+2  A: 

It all depends on the coupling of your components and the flow of your program. The downside to events is that you will increase the complexity of your program, because it is harder to trace exactly what the flow of execution will be when any piece of code can subscribe to your event. The upside is it allows for a more flexible and scalable design, since any piece of code can subscribe to your event.

So here is the thing, if Player is going to be in charge of handling all things related to leveling up, then having a tight coupling between Player and ExperienceBar is ok. Let's say you want to expose an AddIn framework, in that case you probably want to expose leveling up to external plugins, in which case an event makes a lot more sense.

Personally, I would have XP be a part of Player, and have Player expose a LevelUp event, but I don't know if that would be a good idea for you and your framework/domain modeling without seeing your existing code.

Matt Briggs
I would think that XP being a part of player is probably the right way to do this, but I was just thinking of an original way to look at the events handling idea for my own learnin.When I finished building the code, and started to write down what it was I done and the reasoning behind it, I began to realise that it didn't make a lot of practical sense. But thank you for the response Matt!
Andrew Weir
That was my thinking, even if you have ExperienceBar as a subclass of Player, at least encapsulate outside interactions with it inside the Player class, since XP is obviously a property of player
Matt Briggs
A: 

I don't think it makes sense to have Experience bar fire an event - in that case a return value would be fine. It could then call the Player's LevelUp function, which could fire an OnLevelUp event from the Player class, if needed.

Mike Blandford