I have defined an Event class:
Event
and all the following classes inherit from Event:
SportEventType1 SportEventType2 SportEventType3 SportEventType4
Right now I will only have SportEvents but I don't know if in the future I'll want some other kind of events that doesn't even have anything to do with Sports.
Later, I will want to draw some graphics with info taken from Events, and the drawing logic can be a bit complex. But, for the moment, I think I shouldn't think of how the drawing will be done and I believe that maybe it'd be better if that drawing part was not put as an integral part of the Event/SportEventX class chain.
I am looking for solutions for this problem. I know I could just make Event have an instance variable(attribute, for the java crowds) pointing to something as an IDrawInterface, but that would make the Event class "assume" it will be later used for drawing. I would like to make the Event class oblivious to this if possible.
Thanks!
Your intent to keep knowledge of the drawing process outside the Event class hierarchy is good.
A common way to handle this sort of thing in an OO language is the Visitor Pattern.
If you can't actually change the Event class to add the accept(Visitor v) needed for Visitor, you might consider using a Decorator or an Adapter. Getting the accept method to vary by subclass might be painful with these though. I'll think about this a bit more and maybe add further notes tonight. For now, I've got to get to work.
Here's a more complex but pretty flexible approach. We'll define an interface
for a type that can draw some events:
interface IEventRenderer
{
// Draw the given event, if it can. Return true if the event was drawn,
// false otherwise.
bool Draw(Event event);
}
It does two things: it checks to see if it can draw a given event, and, if so,
draws it. Otherwise it bails and returns false.
For example, a class that can render Sport1Events looks like:
class Sport1EventRenderer : IEventRenderer
{
public bool Draw(Event event)
{
var sportEvent = event as Sport1Event;
// can only draw this type
if (sportEvent == null) return false;
// draw the event...
return true;
}
}
Then we'll define a registry class. It's job is to maintain a collection of
these renderers and hand off the work of drawing an event to the appropriate
one:
class EventRendererRegistry
{
public void Add(IEventRenderer renderer)
{
mRenderers.Add(renderer);
}
public void Draw(Event event)
{
foreach (var renderer in mRenderers)
{
if (renderer.Draw(event)) break;
}
}
private readonly List<IEventRenderer> mRenderers = new List<IEventRenderer>();
}
All it does is find the first renderer that can successfully draw the event.
You would then use this like:
var registry = new EventRendererRegistry();
registry.Add(new Sport1EventRenderer());
registry.Draw(someEvent);
Pros:
Event types are not coupled to any rendering code.
Renderers are not coupled to each other.
Renderers are only coupled to the events they care about. (For example a
Sport2EventRenderer would not need to be coupled to Sport1Event.)
Renders can do arbitrary logic to determine if they're appropriate. We're just
doing a type test here, but we could see if the event implements a certain
interface, has a certain property, is in a certain state, etc.
Relatively fast. No reflection beyond simple casting.
Cons:
Fairly complex.
Can fail at runtime to find a matching renderer.
Have to iterate through renderer collection each time to find a match.
One other solution might be to have an DrawbleEvent abstract class where different sportingevents can inherit from.
public abstract DrawableEvent
{
Event event;
IDrawingStrategy drawingstrategy;
public Draw()
{
drawingStrategy.Draw();
}
}
public SportingEvent1 : DrawableEvent
{
SprortingEvent1(Event event, IdrawingStrategy strategy)
{
this.event=event;
this.drawingstrategy = strategy;
}
}
The Event reference can go to the strategy or to the sprorting event depending on where it is needed.
Related
I know that multiple inheritance in C# is only allowed by using Interfaces and that there are very valid reasons why multiple inheritance can quickly become a real headache. (Working in .NET Framework if that makes any difference to the answers)
However.
In working on various projects accross many classes I find myself returning to the same patterns to handle behaviour.
For example I have an Interface IXMLSavable which requires the functions GetXML() and SetFromXML(XElement e) to be implemented. The way I implement this in every class is, that I write different functions for different versions of the XML (If I changed something in the GetXML() I want to maintain backwards compatibility...). And according to a version-attribute on the root Element I switch case to the right ReadVersionX(XElement e) function so all my data stays consitent.
Another example would be centered around eventing. If for example I want to implement a "stop firing events for the time being"-Lock I would go about thusly:
private bool suppressEvents;
public bool SuppressEvents
{
get { return suppressEvents; }
set
{
bool prevValue=SuppressEvents;
suppressEvents=value;
if(prevValue!=SuppressEvents && !SuppressEvents) TheChangeEvent?.Invoke();
}
}
So I can run multiple operations on the object in question without it giving of a right old firework display of events. Again: This code will be almost unchanged for a lot of classes.
For the XML one I could refactor this to a class that has a Dictionary<int,delegate> ReadFunctions which I could then set in every implementation (I concede that there needs to be a bit of customisation in the "implementing" class) and reduce the amount of bolierplate for every class (the explicit switching on the version attribute) to just filling this dictionary.
The eventing one could go into a class on its own quite readily, I would probably only need to hook up the right event to the invokation, but that could easily be remedied by an abstract function I will have to implement (again: customisation still necessary but much less boilerplate).
Each "now-class-was-interface" on its own would make a splendid base class for any object. I could use functionality down an inheritance tree and customise it by overwriting functionality with new if I would need it.
The problem starts when I want to combine the two now-classes together. Due to the limitation in C# (which, again, is there for a reason) I cannot inherit from both above described classes at the same time. This would only be possible if I have one of these classes inherit from the other. Which would be possible, but would lead to a whole lot of a different headache when I want one functionality but not the other. Or the other functionality and not the one. The way around that would be to create a plethora of permutation classes (so one class for each combination of the functionaities). And while that would solve the problem it would probably be a nightmare to maintain.
So the real question is: Is there a way to correctly plug in different already implemented functionality into a class in an inheritance like manner that allows the addition of multiple distinct functionality packages as opposed to interfaces that cannot by the very nature of themselves provide any concrete implementation.
In many cases you can avoid inheritance with the use of interfaces/default interface methods/extension methods, decorators, or some other pattern.
In your case with xml you could simply change your interface to have one ReadMethod per version, and use a extension method to select the correct one
public interface IXMLReadable{
void ReadVersion1(XElement e);
void ReadVersion2(XElement e);
}
public static class IXMLReadableExtensions {
public static void Read(this IXMLReadable self, XElement e){
// Read version from xml, call ReadVersion1 or ReadVersion2
}
}
default interface methods would do more or less the same thing, with the added advantage of allowing the class to override the Read-method if it wants some other behavior.
However, my preferred solution would be to instead convert your object to a Data Transfer Object (DTO), add any required serialization attributes to this object, and use a library to serialize this. Added fields etc can usually be accommodated by just marking it as optional. Larger changes can usually be done by creating a new DTO class.
One way to solve your event problem could be to move this logic to a separate class
public class SuppressibleEvent
{
private bool suppressEvents;
private bool pendingEvent;
public void Raise()
{
if (!suppressEvents)
{
TheChangeEvent?.Invoke(this, EventArgs.Empty);
}
else
{
pendingEvent = true;
}
}
public event EventHandler TheChangeEvent;
public bool SuppressEvents
{
get => suppressEvents;
set
{
suppressEvents = value;
if (!suppressEvents && pendingEvent)
{
TheChangeEvent?.Invoke(this, EventArgs.Empty);
pendingEvent = false;
}
}
}
}
Optionally you may add a interface, so that only the owner can raise the event, but others can listen and register. You could also add methods/events to your class that just forwards to the actual implementation.
The overall point is that there is usually a better pattern to use than implementation inheritance. Some might require a bit more code, but usually gain a bit of flexibility as a result.
Consider I have a game-creation framework, with a basic class called Game.
// Action version
public class Game
{
public Action<float> OnUpdate;
public void Update(float mFrameTime) { OnUpdate.Invoke(mFrameTime); }
}
// Virtual version
public class Game
{
public virtual void Update(float mFrameTime) {}
}
Which one is the best approach?
(design-wise and performance-wise)
Subscribing something to the OnUpdate action (and not inheriting the Game class), or inheriting the Game class and overriding the virtual method?
This depends on who the target audience is for the Update notification. If it's for only derived classes then a virtual method is a fine approach. If it's for derived classes and or arbitrary consumer then the event style pattern is the correct approach.
I would rather raise events than have the Action<T>. This is a common pattern in .NET:
public class Game
{
public event EventHandler<SomeEventArgs> Update;
protected virtual void OnUpdate(float mFrameTime) { // invoke event here }
}
It depends what the rest of your framework looks like and what you plan to do with this class. If this class simply alerts other classes that its time to update, then you'll want an event based system. If this is a base class for all games to derive from, then you'll probably want an override. No answer is 100% correct - it all depends on what exactly you are trying to accomplish with your design.
Unfortunately I lack the knowledge to answer which of those options would be more efficient from a performance perspective, but from a design perspective I would advise overriding the Update method for the following reasons:
It keeps all your update logic in one spot.
It allows you to easily monitor the ordering of update actions.
As others have said, it depends on the purpose of the class, and I am making assumptions based on the fact that it's a 'game' class. There's no reason you couldn't implement both, with a virtual method that triggers an event. This would allow for the bulk of update code to be located centrally, with the option for elements to subscribe to the update event as needed.
When I've approached the same problem myself I've typically adopted a virtual-method approach, though I've broken down update into multiple sections for convenience and control purposes.
I am building an WinForms application with a UI that only consists of a NotifyIcon and its dynamically populated ContextMenuStrip. There is a MainForm to hold the application together, but that is never visible.
I set out to build this as SOLIDly as possible (using Autofac to handle the object graph) and am quite pleased with my success, mostly getting along pretty well even with the O part. With the extension I am currently implementing it seems I have discovered a flaw in my design and need to remodel a bit; I think know the way I need to go but am a bit unclear as to how to exactly define the dependencies.
As mentioned above, the menu is in part populated dynamically after starting the application. For this purpose, I defined an IToolStripPopulator interface:
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
An implementation of this is injected into the MainForm, and the Load() method calls PopulateToolStrip() with the ContextMenuStrip and a handler defined in the form. The populator's dependencies are only related to obtaining the data to use for the menu items.
This abstraction has worked nicely through a few evolutionary steps but isn't sufficient anymore when I need more than one event handler, e.g. because I am creating several different groups of menu items - still hidden behind a single IToolStripPopulator interface because the form shouldn't be concerned with that at all.
As I said, I think I know what the general structure should be like - I renamed the IToolStripPopulator interface to something more specific* and created a new one whose PopulateToolStrip() method does not take an EventHandler parameter, which is instead injected into the object (also allowing for much more flexibility regarding the number of handlers required by an implementation etc.). This way my "foremost" IToolStripPopulator can very easily be an adapter for any number of specific ones.
Now what I am unclear on is the way I should resolve the EventHandler dependencies. I think the handlers should all be defined in the MainForm, because that has all the other dependencies needed to properly react to the menu events, and it also "owns" the menu. That would mean my dependencies for IToolStripPopulator objects eventually injected into the MainForm would need to take dependencies on the MainForm object itself using Lazy<T>.
My first thought was defining an IClickHandlerSource interface:
public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
This was implemented by my MainForm, and my specific IToolStripPopulator implementation took a dependency on Lazy<IClickHandlerSource>. While this works, it is inflexible. I would either have to define separate interfaces for a potentially growing number of handlers (severely violating OCP with the MainForm class) or continuously extend IClickHandlerSource (primarily violating ISP).
Directly taking dependencies on the event handlers looks like a nice idea on the consumers' side, but individually wiring up the constructors via properties of lazy instance (or the like) seems pretty messy - if possible at all.
My best bet currently seems to be this:
public interface IEventHandlerSource
{
EventHandler Get(EventHandlerType type);
}
The interface would still be implemented by MainForm and injected as a lazy singleton, and EventHandlerType would be a custom enum with the different types I need. This would still not be very OCP compliant, but reasonably flexible. EventHandlerType would obviously have a change for each new type of event handler, as would the resolution logic in MainForm, in addition to the new event handler itself and the (probably) newly written additional implementation of IToolStripPopulator.
Or.... a separate implementation of IEventHandlerSource that (as the only object) takes a dependency on Lazy<MainForm> and resolves the EventHandlerType options to the specific handlers defined in MainForm?
I'm trying to think of a way of actually getting the event handlers out of MainForm in a feasible way, but can't quite seem to right now.
What is my best option here, providing the loosest coupling and most elegant resolution of the different event handlers?
[*Yes, I probably should have left the name alone to really comply with OCP, but it looked better that way.]
What is my best option here, providing the loosest coupling and most
elegant resolution of the different event handlers?
Common solution are not exist and it depends on the global application architecture.
If you want a loosest coupling, EventAggregator pattern can help you in such case (your IEventHandlerSource similar to that):
Pattern Description - http://martinfowler.com/eaaDev/EventAggregator.html
Implementation in Prism - http://msdn.microsoft.com/en-us/library/ff921122.aspx
But, global events should be used with great caution - they can smudge architecture, because subscribe to the event will be possible anywhere.
Important thing in DI and IoC: lower dependency should not to know about higher dependency.
I think, and as Leon said earlier, will be better to create some interface like ITool<T> and store list of tools in the MainForm. After some action MainForm will invoke certain methods in this tools.
Firstly, I think you shouldn't claim your mainform must contain all event handlers. You clearly ran into the fact that there are different handlers with different needs (and probably different dependencies), so why should they all be fitted into the same class?
You can probably take some inspiration from the way events are handled in other languages. WPF uses Commands, Java has Listeners. Both are objects, not just a delegate, making them easier to deal with in an IOC scenario. It's fairly easy to simulate something like that. You could abuse the tag on your toolbar items, like this: Binding to commands in WinForms or use lambda expressions inside PopulateToolbar (see Is there anything wrong with using lambda for winforms event?) to associate the toolbar item with the correct command. That's assuming that since PopulateToolbar knows which items need to be created it also know which action/command belongs to each item.
The object representing the action can have their own dependencies injected, independently of the main form or other actions. Toolbar items with their own actions can then be added or removed later without affecting your main form or any of the other actions, each action can independently be tested and refactored.
Bottom line, stop thinking about EventHandlers, start thinking about Actions/Commands as an entity in their own right and it will become easier to come up with a suitable pattern. Make sure you understand the Command Pattern, because that's pretty much what you need here.
Have you tried to use an event aggregator? See: Caliburn framework, event Aggregator
An event aggregator will decouple the toolstrip from you main form.
public interface IToolStripPopulator
{
ToolStrip PopulateToolStrip(ToolStrip toolstrip);
}
Wrap the aggregator for convenience like this:
public static class Event
{
private static readonly IEventAggregator aggregator = new EventAggregator();
public static IEventAggregator Aggregator
{
get
{
return aggregator;
}
}
}
You define one or more event classes, for example:
public class EventToolStripClick {
public object Sender {get;set;}
public EventArgs Args {get;set;}
}
In the controller that creates the toolstrip, publish the custom event in the Click handler write:
public void ControllerToolStripClick(object sender, EventArgs args )
{
Event.Aggregator.Publish(new EventToolStripClick(){Sender=sender,Args=args)});
}
In the mainForm implement the interface IHandle
public class MainForm : Form, IHandle<EventToolStripClick>
{
...
public void Handle(EventToolStripClick evt)
{
//your implementation here
}
}
If you are hosting child components within your form, and they can populate the main application "shell".
You could have a base class ShellComponent, that inherits from System.Windows.Forms.ContainerControl. This will give you a design surface as well. Instead of relying IToolStripPopulator, you could have ITool like such.
public inteface ITool<T>
{
int ToolIndex { get; }
string Category { get; }
Action OnClick(T eventArgs);
}
In ShellComponent you could call, public List<ITool> OnAddTools(ToolStrip toolStrip) from the MainForm each time a view is loaded. This way the component would be responsible for populating the toolstrip.
The 'ShellComponent' would then ask the IoC container for handlers that implement ITool<T>. This way your ITool<T> provides a way to separate the event (in the MainForm, or the ContainerControl) and push this out to any class. It also allows you to define exactly what you want to pass through for arguments (as opposed to MouseClickEventArgs ect).
Right now I have six classes:
Listener - manages socket connections
World - a collection of entities and tasks
Ticker - coordinates updating the world
MessageProcessor - receives commands from players
Intelligence - governs the behavior of non-player characters
Tasks - tracking and execution of tasks
But they are like spaghetti with reference to each other all over the place... The World is a data model which the MessageProcessor, Intelligence, and Tasks classes modify. The Ticker coordiates those three classes updating the World. The Listener is used by the MessageProcessor for incomming messages, and by the other classes to push updates.
How can I improve this situation?
I gave a related answer not long ago. The subject was on improving the testability of code, for which the general solution is to loosen coupling. The main focus on that previous answer was on decoupling networking related code from the world and it's logic, because networking code is not unit testable and is a pain to mock too.
The solution given there was to use an interface for incoming messages, such that you decouple the MessageProcessor (named Handler in other post) from the network code, and similarly, decouple the UpdateNotifier from the World.
The dashed line is just an indirect reference handled either by an interface or delegate. There exists no direct relation between the World and networking component now, making it testable. This is really just an application of the Model View Adapter pattern.
This doesn't seem dissimilar to the design you've described having, except perhaps you are missing a few interfaces. With this pattern of interface based UpdateNotifiers used to push updates, I essentially reuse the same architecture for handling NPCs, tasks, or anything else which is processed elsewhere. You cherry pick the event notifiers you need for a particular area, and implement a concrete Notifier class for them, such that you have multiple adapters on the same model.
And that really only looks more complicated than it is. The World object has no direct dependencies on anything else, and each other class has at most one direct dependency. You can also isolate the timer from the World, as it probably isn't needed there - but perhaps one of the biggest hurdles is handling synchronization between the different adapters.
Well, I'm not sure I have a full picture of what the issues you are having are, but I have a few possibilities from what you have laid out so far. (I may be actually suggesting some things that are already done since I'm not sure I have enough from the one-liner descriptions to understand fully.
The Model
I would say from what you've described, the main thing that strikes me is that you'll want to start implementing common functionality in a class model; you will want either interfaces or base classes that you can use to derive your high-level objects from.
This way you can handle things consistently with little extra effort. I think the idea of "architectural layers" can be useful as a first cut of how to think about it, (e.g. low-level hardware stuff, socket handling etc., then middle-layers stuff like what kind of things happen in your game, and the details behind how game mechanics work, etc., and high-level stuff like what can the PC or NPCs do, what's the environment doing, etc.. and also the idea that you never want to "jump" layers). However, when it comes down to it the important thing is to just find the right abstractions for your game, and keep everything organized in such a way as you never feel like the bit of code you're working on is doing two completely different kinds of things.
So, first, let's take the fact that it sounds like (naturally) there are a lot of things interacting with world state. For something like this, it's probably advantageous to factor a lot of the 'stuff' out into a single class, and then mostly only have the one class doing that job. Ideally you implement, say, event communication/message passing, in it's own little group, so that there's no need to pollute your higher-level objects with the nitty-gritty of handling stuff.
e.g., you want to focus on what things are doing at a high level in the higher-level objects: in an AI perhaps "begin movement toward a location", "set my haste", "stop movement"; and in an environment subsystem do "start raining", "increase windspeed", "dim lights"; in a user class "fire weapon", "sleep", "cast spell". But I wouldn't want any of my high-level classes to even know about things like "send message to world", or "reset thirst timer", or "receive socket data", or "health cycle tick". (These are all just elucidations, not suggestions. ;D)
Events
For instance, I think it may be valuable to keep one object in charge of dispatching events to the World, that way you no longer have everyone talking to everyone. I would likely just create a set of stuff to handle events in general. So, maybe EventMain and an enumEvents that you use so that each type of event has a special ID. And then use Event as the base class for particular events that need extra functionality. (I have both the ID as well as a derivation model in mind, so that things thing like the Dispatcher which likely only need to know very basic things about the event don't have to also know about the derived classes. For instance, the dispatcher could take an event in and send it out without ever having to know the internals of a derived event. This may or may not turn out to be useful, but it's good to have the options.) You could also have an EventDispatcher that has a queue of events to be send to other subsystems.
You will want something common for recieving and sending events. You could do EventSourcer and EventSinker standalone classes that can be set up in any class that is generating or receiving events. Or, you could instead do IEventSource and IEventSink so that you could implement a common interface on multiple classes, or perhaps a common class EventSourceAndSink that implements both, and which is part of your base class model, so that anything that might need to handle events can just derive from it.
I would probably make ProtocolEncoder and ProtocolDecoder classes. You can always combine them into a single object, but it may be valuable, and shouldn't cause any issues if done adequately, to have them be two separate pieces of code. You could also have a ProtocolHelper class that factors out anything in common between the two. The encoders sole job is to receive messages from the network and turn them into events for your game, which it will then pass on to the EventDispatcher. The decoder class will take events from the dispatcher that need to go out to the network, and it will take the data from them and send it out.
How to Get Where You're Going
Since you do have working code, I would recommend that you just start doing it wherever seems natural. That could be things that are bogging you down, or things you've noticed to be very similar in different places that you could make regular with a class or some other type of abstraction, then pull out the old and put in the new. Once you have figured out a workable first cut of a class model, that should give you ideas based on what you already have and as you go be constantly reconsidering your model, fixing the things that are a problem, lather, rinse, repeat.
It doesn't have to be a lot of work, in fact, some of the most gratifying moments I've had working on code was when I was able to do a neat refactor that left a formerly hideous mess in much better shape, removing a lot of hard-to-understand code, and replacing it with something that's easier to understand, in fewer lines of code, and that opened up a path toward my next addition being a pleasure instead of another "zomg I don't have to touch that code again do I?" moment.
Best of luck, follows is a nominal guide to the things I was talking about; the first bit is more detailed because the main event class is one of the more important concepts, and then I try to just give a nominal overview of the classes and how they interact. I'm sure I could spend even more hours on this, but at this point I'll just say: ask me if you have questions and I'll do what I can to give you a good answer :)
Ideas in Code
Oh, one more thing of note is I didn't deal at all with the complexities added if you have multiple threads; there are things ranging from simple to intricate to manage it all if you do, but that's another exercise. :)
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
// this is internal to the project namespace, say, TimsWorld_o_Hurt
// I'm now resisting calling everything Xxxx_o_Hurt :)
// examples o' hurt
using EventHandlingLibrary;
namespace EventHandlingLibrary
{
// this will provide the base class for all the events, and can
// also have static methods like factory methods, destination
// lookups etc.
// I have the enums set to protected with the intent being that
// specific factory functions should be called by other classes.
// You should change this if it turns out to be too cumbersome.
public class EventOfHurt
{
#region Event Definitions
protected enum EEventType
{
// System Events
SystemInitializing,
SubsystemInitComplete,
FatalErrorNotification,
SubsystemPingReponse,
SubsystemPingRequest,
// Network Events
FrameRateError,
ThroughputData,
ServerTimeout,
ServerPingRequest,
ServerPingResponse,
// User Events
WeaponsFire,
MovementNotification,
FatigueUpdate
// and so forth
}
protected enum ESubsystem
{
System,
Dispatcher,
TickerTimer,
WorldEntity,
WorldTaskManager,
UserMessageProcessor,
NetworkListener,
NetworkTransmitter,
ProtocolEncoder,
ProtocolDecoder,
PlayerCharacter,
NonPlayerCharacter,
EventSink,
EventSource
// and such
}
#endregion
#region Event Information
public Guid EventId { get; protected set; }
public EEventType EventType { get; protected set; }
public ESubsystem SourceSubsystem { get; protected set; }
public ESubsystem DestSubsystem { get; protected set; }
private List<Tuple<EventOfHurt, DateTime>>
myEventReferences;
// the event(s) that triggered it, if any, and when rec'd
public Tuple<EventOfHurt, DateTime>[]
EventReferences
{
get { return myEventReferences.ToArray(); }
}
public DateTime Timestamp { get; private set; }
#endregion
// we'll be using factor methods to create events
// so keep constructors private; no default constructor
private EventOfHurt(
EEventType evt,
ESubsystem src,
ESubsystem dest = ESubsystem.Dispatcher
)
{
EventType = evt;
SourceSubsystem = src;
DestSubsystem = dest;
EventId = Guid.NewGuid();
Timestamp = DateTime.UtcNow;
}
// called to create a non-derived event for simple things;
// but keep other classes limited to calling specific factory
// methods
protected static EventOfHurt CreateGeneric(
EEventType evt, ESubsystem src,
ESubsystem dest = ESubsystem.Dispatcher,
Tuple<EventOfHurt, DateTime>[] reasons = null
)
{
EventOfHurt RetVal;
if (dest == null)
dest = ESubsystem.Dispatcher;
List<Tuple<EventOfHurt, DateTime>> ReasonList =
new List<Tuple<EventOfHurt,DateTime>>();
if (reasons != null)
ReasonList.AddRange(reasons);
// the initializer after the constructor allows for a
// lot more flexibility than e.g., optional params
RetVal = new EventOfHurt(evt, src) {
myEventReferences = ReasonList
};
return RetVal;
}
// some of the specific methods can just return a generic
// non-derived event
public static EventOfHurt CreateTickerTimerEvent(
EEventType evt, ESubsystem dest
)
{
ESubsystem src = ESubsystem.TickerTimer;
return CreateGeneric(evt, src, dest, null);
}
// some may return actual derived classes
public static EventOfHurt CreatePlayerActionEvent(
EEventType evt, ESubsystem dest,
Tuple<EventOfHurt, DateTime>[] reasons
)
{
PlayerEvent PE = new PlayerActionEvent(42);
return PE;
}
}
// could have some specific info relevant to player
// events in this class, world location, etc.
public class PlayerEvent :
EventOfHurt
{
};
// and even further speciailzation here, weapon used
// speed, etc.
public class PlayerActionEvent :
PlayerEvent
{
public PlayerActionEvent(int ExtraInfo)
{
}
};
}
namespace EntitiesOfHurt
{
public class LatchedBool
{
private bool myValue = false;
public bool Value
{
get { return myValue; }
set {
if (!myValue)
myValue = value;
}
}
}
public class EventOfHurtArgs :
EventArgs
{
public EventOfHurtArgs(EventOfHurt evt)
{
myDispatchedEvent = evt;
}
private EventOfHurt myDispatchedEvent;
public EventOfHurt DispatchedEvent
{
get { return myDispatchedEvent; }
}
}
public class MultiDispatchEventArgs :
EventOfHurtArgs
{
public MultiDispatchEventArgs(EventOfHurt evt) :
base(evt)
{
}
public LatchedBool isHandled;
}
public interface IEventSink
{
// could do this via methods like this, or by attching to the
// events in a source
void MultiDispatchRecieve(object sender, MultiDispatchEventArgs e);
void EventOfHurt(object sender, EventOfHurtArgs e);
// to allow attaching an event source and notifying that
// the events need to be hooked
void AttachEventSource(IEventSource evtSource);
void DetachEventSource(IEventSource evtSource);
}
// you could hook things up in your app so that most requests
// go through the Dispatcher
public interface IEventSource
{
// for IEventSinks to map
event EventHandler<MultiDispatchEventArgs> onMultiDispatchEvent;
event EventHandler<EventOfHurtArgs> onEventOfHurt;
void FireEventOfHurt(EventOfHurt newEvent);
void FireMultiDispatchEvent(EventOfHurt newEvent);
// to allow attaching an event source and notifying that
// the events need to be hooked
void AttachEventSink(IEventSink evtSink);
void DetachEventSink(IEventSink evtSink);
}
// to the extent that it works with your model, I think it likely
// that you'll want to keep the event flow being mainly just
// Dispatcher <---> Others and to minimize except where absolutely
// necessary (e.g., performance) Others <---> Others.
// DON'T FORGET THREAD SAFETY! :)
public class Dispatcher :
IEventSource, IEventSink
{
}
public class ProtocolDecoder :
IEventSource
{
}
public class ProtocolEncoder :
IEventSink
{
}
public class NetworkListener
{
// just have these as members, then you can have the
// functionality of both on the listener, but the
// listener will not send or receive events, it will
// focus on the sockets.
private ProtocolEncoder myEncoder;
private ProtocolDecoder myDecoder;
}
public class TheWorld :
IEventSink, IEventSource
{
}
public class Character
{
}
public class NonPlayerCharacter :
Character,
IEventSource, IEventSink
{
}
public class PlayerCharacter :
Character,
IEventSource, IEventSink
{
}
}
I am programming a simple role playing game (to learn and for fun) and I'm at the point where I'm trying to come up with a way for game objects to interact with each other. There are two things I am trying to avoid.
Creating a gigantic game object that can be anything and do everything
Complexity - so I am staying away from a component based design like you see here
So with those parameters in mind I need advice on a good way for game objects to perform actions on each other.
For example
Creatures (Characters, Monsters, NPCs) can perform actions on Creatures or Items (weapons, potions, traps, doors)
Items can perform actions on Creatures or Items as well. An example would be a trap going off when a character tries to open a chest
What I've come up with is a PerformAction method that can take Creatures or Items as parameters. Like this
PerformAction(Creature sourceC, Item sourceI, Creature targetC, Item targetI)
// this will usually end up with 2 null params since
// only 1 source and 1 target will be valid
Or should I do this instead?
PerformAction(Object source, Object target)
// cast to correct types and continue
Or is there a completely different way I should be thinking about this?
This is a "double dispatch" problem. In regular OO programming, you "dispatch" the operation of a virtual method call to the concrete type of the class implementing the object instance you call against. A client doesn't need to know the actual implementation type, it is simply making a method call against an abstract type description. That's "single dispatch".
Most OO languages don't implement anything but single-dispatch. Double-dispatch is when the operation that needs to be called depends on two different objects. The standard mechanism for implementing double dispatch in OO languages without direct double-dispatch support is the "Visitor" design pattern. See the link for how to use this pattern.
This sounds like a case for polymorphism. Instead of taking Item or Creature as an argument, make both of them derive (or implement) from ActionTarget or ActionSource. Let the implementation of Creature or Item determine which way to go from there.
You very rarely want to leave it so open by just taking Object. Even a little information is better than none.
You can try mixing the Command pattern with some clever use of interfaces to solve this:
// everything in the game (creature, item, hero, etc.) derives from this
public class Entity {}
// every action that can be performed derives from this
public abstract class Command
{
public abstract void Perform(Entity source, Entity target);
}
// these are the capabilities an entity may have. these are how the Commands
// interact with entities:
public interface IDamageable
{
void TakeDamage(int amount);
}
public interface IOpenable
{
void Open();
}
public interface IMoveable
{
void Move(int x, int y);
}
Then a derived Command downcasts to see if it can do what it needs to the target:
public class FireBallCommand : Command
{
public override void Perform(Entity source, Entity target)
{
// a fireball hurts the target and blows it back
var damageTarget = target as IDamageable;
if (damageTarget != null)
{
damageTarget.TakeDamage(234);
}
var moveTarget = target as IMoveable;
if (moveTarget != null)
{
moveTarget.Move(1, 1);
}
}
}
Note that:
A derived Entity only has to implement the capabilities that are appropriate for it.
The base Entity class doesn't have code for any capability. It's nice and simple.
Commands can gracefully do nothing if an entity is unaffected by it.
I think you're examining too small a part of the problem; how do you even determine the arguments to the PerformAction function in the first place? Something outside of the PerformAction function already knows (or somehow must find out) whether the action it wants to invoke requires a target or not, and how many targets, and which item or character it's operating upon. Crucially, some part of the code must decide what operation is taking place. You've omitted that from the post but I think that is the absolute most important aspect, because it's the action that determines the required arguments. And once you know those arguments, you know the form of the function or method to invoke.
Say a character has opened a chest, and a trap goes off. You presumably already have code which is an event handler for the chest being opened, and you can easily pass in the character that did it. You also presumably already ascertained that the object was a trapped chest. So you have the information you need already:
// pseudocode
function on_opened(Character opener)
{
this.triggerTrap(opener)
}
If you have a single Item class, the base implementation of triggerTrap will be empty, and you'll need to insert some sort of checks, eg. is_chest and is_trapped. If you have a derived Chest class, you'll probably just need is_trapped. But really, it's only as difficult as you make it.
Same goes for opening the chest in the first place: your input code will know who is acting (eg. the current player, or the current AI character), can determine what the target is (by finding an item under the mouse, or on the command line), and can determine the required action based on the input. It then simply becomes a case of looking up the right objects and calling the right method with those arguments.
item = get_object_under_cursor()
if item is not None:
if currently_held_item is not None:
player_use_item_on_other_item(currently_held_item, item)
else
player.use_item(item)
return
character = get_character_under_cursor()
if character is not None:
if character.is_friendly_to(player):
player.talk_to(character)
else
player.attack(character)
return
Keep it simple. :)
in the Zork model, each action one can do to an object is expressed as a method of that object, e.g.
door.Open()
monster.Attack()
something generic like PerformAction will end up being a big ball of mud...
What about having a method on your Actors (creatures, items) that Perform the action on a target(s). That way each item can act differently and you won't have one big massive method to deal with all the individual items/creatures.
example:
public abstract bool PerformAction(Object target); //returns if object is a valid target and action was performed
I've had a similar situation to this, although mine wasn't Role playing, but devices that sometimes had similar characteristics to other devices, but also some characteristics that are unique. The key is to use Interfaces to define a class of actions, such as ICanAttack and then implement the particular method on the objects. If you need common code to handle this across multiple objects and there's no clear way to derive one from the other then you simply use a utility class with a static method to do the implementation:
public interface ICanAttack { void Attack(Character attackee); }
public class Character { ... }
public class Warrior : Character, ICanAttack
{
public void Attack(Character attackee) { CharacterUtils.Attack(this, attackee); }
}
public static class CharacterUtils
{
public static void Attack(Character attacker, Character attackee) { ... }
}
Then if you have code that needs to determine whether a character can or can't do something:
public void Process(Character myCharacter)
{
...
ICanAttack attacker = null;
if ((attacker = (myCharacter as ICanAttack)) != null) attacker.Attack(anotherCharacter);
}
This way, you explicitly know what capabilities any particular type of character has, you get good code reuse, and the code is relatively self-documenting. The main drawback to this is that it is easy to end up with objects that implement a LOT of interfaces, depending on how complex your game is.
This might not be something that many would agree upon, but I'm not a team and it works for me (in most cases).
Instead of thinking of every Object as a collection of stuff, think of it as a collection of references to stuff. Basically, instead of one huge list of many
Object
- Position
- Legs
- [..n]
You would have something like this (with values stripped, leaving only relationships):
Whenever your player (or creature, or [..n]) wants to open a box, simply call
Player.Open(Something Target); //or
Creature.Open(Something Target); //or
[..n].Open(Something Target);
Where "Something" can be a set of rules, or just an integer which identifies the target (or even better, the target itself), if the target exists and indeed can be opened, open it.
All this can (quite) easily be implemented through a series of, say interfaces, like this:
interface IDraggable
{
void DragTo(
int X,
int Y
);
}
interface IDamageable
{
void Damage(
int A
);
}
With clever usage of these interfaces you might even ending up using stuff like delegates to make an abstraction between top-level
IDamageable
and the sub-level
IBurnable
Hope it helped :)
EDIT: This was embarassing, but it seems I hijacked #munificent's answer! I'm sorry #munificent! Anyway, look at his example if you want an actual example instead of an explanation of how the concept works.
EDIT 2: Oh crap. I just saw that you clearly stated you didn't want any of the stuff that was contained in the article you linked, which clearly is exactly the same as I have written about here! Disregard this answer if you like and sorry for it!