Related
In many different projects I have seen 2 different approaches of raising Domain Events.
Raise Domain Event directly from aggregate. For example imagine you have Customer aggregate and here is a method inside it:
public virtual void ChangeEmail(string email)
{
if(this.Email != email)
{
this.Email = email;
DomainEvents.Raise<CustomerChangedEmail>(new CustomerChangedEmail(email));
}
}
I can see 2 problems with this approach. The first one is that the event is raised regardless of whether the aggregate is persisted or not. Imagine if you want to send an email to a customer after successful registration. An event "CustomerChangedEmail" will be raised and some IEmailSender will send the email even if the aggregate wasn't saved. The second problem with the current implementation is that every event should be immutable. So the question is how can I initialize its "OccuredOn" property? Only inside aggregate! Its logical, right! It forces me to pass ISystemClock (system time abstraction) to each and every method on aggregate! Whaaat??? Don't you find this design brittle and cumbersome? Here is what we'll come up with:
public virtual void ChangeEmail(string email, ISystemClock systemClock)
{
if(this.Email != email)
{
this.Email = email;
DomainEvents.Raise<CustomerChangedEmail>(new CustomerChangedEmail(email, systemClock.DateTimeNow));
}
}
The second approach is to go what Event Sourcing pattern recommends to do. On each and every aggregate, we define a (List) list of uncommited events. Please payAttention that UncommitedEvent is not a domain Event! It doesn't even has OccuredOn property. Now, when ChangeEmail method is called on Customer Aggregate, we don't raise anything. We just save the event to uncommitedEvents collection which exists on our aggregate. Like this:
public virtual void ChangeEmail(string email)
{
if(this.Email != email)
{
this.Email = email;
UncommitedEvents.Add(new CustomerChangedEmail(email));
}
}
So, when does the actual domain event is raised??? This responsibility is delegated to persistence layer. In ICustomerRepository we have access to ISystemClock, because we can easily inject it inside repository. Inside Save() method of ICustomerRepository we should extract all uncommitedEvents from Aggregate and for each of them create a DomainEvent. Then we set up OccuredOn property on newly created Domain Event. Then, IN ONE TRANSACTION we save the aggregate and publish ALL domain events. This way we'll be sure that all events will will raised in transnational boundary with aggregate persistence.
What I don't like about this approach? I don't want to create 2 different types for the same event, i.e for CustomerChangedEmail behavior I should have CustomerChangedEmailUncommited type and CustomerChangedEmailDomainEvent. It would be nice to have just one type. Please share your experience regarding to this topic!
I am not a proponent of either of the two techniques you present :)
Nowadays I favour returning an event or response object from the domain:
public CustomerChangedEmail ChangeEmail(string email)
{
if(this.Email.Equals(email))
{
throw new DomainException("Cannot change e-mail since it is the same.");
}
return On(new CustomerChangedEmail { EMail = email});
}
public CustomerChangedEmail On(CustomerChangedEmail customerChangedEmail)
{
// guard against a null instance
this.EMail = customerChangedEmail.EMail;
return customerChangedEmail;
}
In this way I don't need to keep track of my uncommitted events and I don't rely on a global infrastructure class such as DomainEvents. The application layer controls transactions and persistence in the same way it would without ES.
As for coordinating the publishing/saving: usually another layer of indirection helps. I must mention that I regard ES events as different from system events. System events being those between bounded contexts. A messaging infrastructure would rely on system events as these would usually convey more information than a domain event.
Usually when coordinating things such as sending of e-mails one would make use of a process manager or some other entity to carry state. You could carry this on your Customer with some DateEMailChangedSent and if null then sending is required.
The steps are:
Begin Transaction
Get event stream
Make call to change e-mail on customer, adding even to event stream
record e-mail sending required (DateEMailChangedSent back to null)
Save event stream (1)
Send a SendEMailChangedCommand message (2)
Commit transaction (3)
There are a couple of ways to do that message sending part that may include it in the same transaction (no 2PC) but let's ignore that for now.
Assuming that previously we had sent an e-mail our DateEMailChangedSent has a value before we start we may run into the following exceptions:
(1) If we cannot save the event stream then here's no problem since the exception will rollback the transaction and the processing would occur again.
(2) If we cannot send the message due to some messaging failure then there's no problem since the rollback will set everything back to before we started.
(3) Well, we've sent our message so an exception on commit may seem like an issue but remember that we could not set our DateEMailChangedSent back to null to indicate that we require a new e-mail to be sent.
The message handler for the SendEMailChangedCommand would check the DateEMailChangedSent and if not null it would simply return, acknowledging the message and it disappears. However, if it is null then it would send the mail either interacting with the e-mail gateway directly ot making use of some infrastructure service endpoint through messaging (I'd prefer that).
Well, that's my take on it anyway :)
I have seen 2 different approaches of raising Domain Events.
Historically, there have been two different approaches. Evans didn't include domain events when describing the tactical patterns of domain-driven-design; they came later.
In one approach, Domain Events act as a coordination mechanism within a transaction. Udi Dahan wrote a number of posts describing this pattern, coming to the conclusion:
Please be aware that the above code will be run on the same thread within the same transaction as the regular domain work so you should avoid performing any blocking activities, like using SMTP or web services.
event-sourcing, the common alternative, is actually a very different animal, in so far as the events are written to the book of record, rather than merely being used to coordinate activities in the write model.
The second problem with the current implementation is that every event should be immutable. So the question is how can I initialize its "OccuredOn" property? Only inside aggregate! Its logical, right! It forces me to pass ISystemClock (system time abstraction) to each and every method on aggregate!
Of course - see John Carmack's plan files
If you don't consider time an input value, think about it until you do - it is an important concept
In practice, there are actually two important time concepts to consider. If time is part of your domain model, then it's an input.
If time is just meta data that you are trying to preserve, then the aggregate doesn't necessarily need to know about it -- you can attach the meta data to the event elsewhere. One answer, for example, would be to use an instance of a factory to create the events, with the factory itself responsible for attaching the meta data (including the time).
How can it be achieved? An example of a code sample would help me a lot.
The most straight forward example is to pass the factory as an argument to the method.
public virtual void ChangeEmail(string email, EventFactory factory)
{
if(this.Email != email)
{
this.Email = email;
UncommitedEvents.Add(factory.createCustomerChangedEmail(email));
}
}
And the flow in the application layer looks something like
Create metadata from request
Create the factory from the metadata
Pass the factory as an argument.
Then, IN ONE TRANSACTION we save the aggregate and publish ALL domain events. This way we'll be sure that all events will will raised in transnational boundary with aggregate persistence.
As a rule, most people are trying to avoid two phase commit where possible.
Consequently, publish isn't usually part of the transaction, but held separately.
See Greg Young's talk on Polyglot Data. The primary flow is that subscribers pull events from the book of record. In that design, the push model is a latency optimization.
I tend to implement domain events using the second approach.
Instead of manually retrieving and then dispatching all events in the aggregate roots repository I have a simple DomainEventDispatcher(application layer) class which listens to various persistence events in the application. When an entity is added, updated or deleted it determines whether it is an AggregateRoot. If so, it calls releaseEvents() which returns a collection of domain events that then get dispatched using the application EventBus.
I don't know why you are focusing so much on the occurredOn property.
The domain layer is only concerned with the meat of the domain events such as aggregate root IDs, entity IDs and value object data.
At the application layer you can have an event envelope which can wrap any serialized domain event while giving it some meta data such as a unique ID (UUID/GUID), what aggregate root it came from, the time it occurred etc. This can be persisted to a database.
This meta data is useful in the application layer because you might be publishing these events to other applications using a message bus/event stream over HTTP and it allows each event to be uniquely identifiable.
Again, this meta data about the event generally makes no sense in the domain layer, only the application layer. The domain layer does not care or have any use for event IDs or the time they occurred but other applications which consume these events do. That's why this data is attached at the application layer.
The way I would solve the sending of email problem is by decoupling the publishing of the event and the handling of the event through a messaging queue. This way you close the transaction after sending the event to the queue, and the sending of email, or other effects that cannot or should not be part of the original DB transaction, will happen shortly after, in a different transaction. The simplest way to do that, of course, is to have an event handler that publishes domain events onto the queue.
If you want to be extra sure that the domain events will be published to the queue when the transaction is committed, you can save the events to an OUTBOX table that will be committed with the transaction, and then have a thread read from the table and publish to the event queue
is there any need to handle locks in terms of threading in any inventory application.
like as i think asp.net is not thread safe.
lets say that there is a product available and its quantity available is 1 and number of user partially trying to book that particular product are 40. so which is going to get that product. or what happens.
not sure even if the question is reliable or not.
http://blogs.msdn.com/b/benchr/archive/2008/09/03/does-asp-net-magically-handle-thread-safety-for-you.aspx
i am not sure on this please help.
Well, technically, you're not even talking about ASP.NET here, but rather Entity Framework or whatever else you're using to communicate with SQL Server or whatever else persistent data store you're using. Relational databases will typically row-lock, so that as one client is updating the row, the row cannot be read by another client, but you can still run into concurrency issues.
You can handle this situation one of two ways: pessimistic concurrency or optimistic concurrency. With pessimistic concurrency you create locks and any other thread trying to read/write the same data is simply turned away in the mean time. In a multi-threaded environment, it's far more common to use optimistic concurrency, since this allows a bit of play room for failover.
With optimistic concurrency, you version the data. As a simplistic example, let's say that I'm looking for the current stock of widgets in my dbo.Widgets table. I'd have a column like Version which might initially be set to "1" and 100 widgets in my Stock column. Client one wants to buy a widget, so I read the row and note the version, 1. Now, I want to update the column so I do an update to set Stock to 99 and Version to 2, but I include in my where clause Version = 1. But, between the time the row was initially read and the update was sent, another client bought a widget and updated the version of the row to 2. The first client's update fails, because Version is no longer 1. So the application then reads the row fresh and tries to update it again, subtracting 1 from Stock and incrementing Version by 1. Rinse and repeat. Generally, you'll want to have some upward limit of attempts before you'll just give up and return an error to the user, but in most scenarios, you might have one collision and then the next one goes through fine. Your server would have to be getting slammed with people eagerly trying to buy widgets before it would be a real problem.
Now of course, this is a highly simplistic approach, and honestly, not something you really have to manage yourself. Entity Framework, for example, will handle concurrency for you automatically as long as you have a rowversion column:
[Timestamp]
public byte[] RowVersion { get; set; }
See http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application for the full guide to setting it up.
ASP.NET certainly is not Thread Safe. The article you link too is fine as a start, but doesn't tell all the story by a long way. In your case, you likely load the Product List into memory at first request for it, or at Application Startup or some other trigger.
When a Request wants to work with a product you grab the appropriate member of this preloaded list. (Believe me this is better than having every request loading the product or product list from the database.) However, now if you have 40 simultaneous requests for the same product they will all be accessing the same object, and new nasty things can happen, like ending up with -39 stock.
You can address this in a many ways ways, but they boild down to two:
Protect the data somehow
Do what Amazon does
Protect the data
There are numerous ways of doing this. One would be to use a critical section via the Lock keyword on C#. For an example, something like this in the Product Class:
private object lockableThing; // Created in the ctor
public bool ReduceStockLevelForSale(int qtySold)
{
bool success = false;
if (this.quantityOnHand >= qtySold)
{
lock (lockableThing)
{
if (this.quantityOnHand >= qtySold)
{
this.quantityOnHand -= qtySold;
success = true;
}
}
}
return success;
}
The double check on the quantity on hand is deliberate and required. There are any number of ways of doing the equivalent. Books have been written about this sort of thing.
Do what Amazon does
As long as at some point in the Order Taking sequence, Amazon thinks it has enough on hand (or maybe even any) it will let you place the order. It doesn't reduce the stock level while the order is being confirmed. Once the order has been confirmed, it has a back-end process (i.e. NOT run by the Web Site) which checks order by order that the order can be fulfilled, and only reduces the On Hand level if it can. If it can't be, they put the order on hold and send you an email saying 'Sorry! We don't have enough of Product X!' and giving you some options.
Discussion
Amazon's is the best way, because if you decrement the stock from the Web Site at what point do you do it? Probably not until the order is confirmed. If the stock has gone, what do you then do? Also, you are going to have to have some functionality to send the 'Sorry!' email: what happens when the last one (or two or three) items of that product can't be found, don't physically exist or are broken? You send a 'Sorry!' email.
However, this does assume that you are in control of the full order to dispatch cycle which is not always the case. If you aren't in control of the full cycle, you need to adjust to what you are in control of, and then pick a method.
I'm currently tinkering around with Workflow Foundation. I have an activity which contains the argument:
System.Activities.InArgument<double> Temperature
However, I want to get the value of this argument in my activity in order to do some validation with it (and also set properties in my activity based on this argument). I understand there is a Get method which takes an ActivityContext, so the actual value would be known at runtime. My question is, how can I get the ActivityContext, or is there a better way?
Note: I'm hosting the WorkflowDesigner in my app which I drop my activities on. So Activity1 contains a property "Temperature", and this is passed into Activity2 as an InArgument. I then validate Activity2, but so far can't get the ActivityContext. I don't need it at execution time, but at design time.
Thanks in advance.
It sounds like you are wanting to use dependency properties like they had in WF3 to tie the output of activity1 to the input of activity2 at design time. Is that correct?
In the WF4 re-write they ripped out all of the dependency property stuff that allowed this.
Speaking specifically to getting access to the ActivityContext item at design time: I don't believe that is going to be possible. The AC object is created at the time of activity execution. It is what allows one instance of an activity to be executed multiple times (each iteration of a loop has a separate AC object associated with it because the AC object is created during runtime).
Here is a good Microsoft blog article describing the difference between WF3 and WF4 activity run-time execution. I think it might help clarify what you are wanting to do and how to approach the problem.
Can you pass the ActivityContext to Activity2 as an argument?
What about using Custom Activity Designers?
EDIT: If you can't be bothered to read this mammoth question, I've put a summary at the bottom.
I'm currently working on a sort of "framework" for a text adventure I am going to make in C#, as a coding excercise. In this framework, possible actions are defined by an "Interaction" class.
The potential "Actionable" objects are Inventory Items (stick, gun, sword), Environmental Items (wall, door, window) and Characters (people, animals). Each of these has a property which is a List of Interactions. At the moment, an Interaction is basically an "action/response" name value pair. When you type "smash window", it looks through all possible actionable items that the Player has available and matches the subject (in this case, "Window"). It then works out that the action is "Smash" and looks up in the List of Interactions on the Window (Environmental Item) to get a response for the Smash action and then writes it to the console.
That is all done, but here is the point that I am stuck:
An action has any number of potential consequences, which differs by each potential interaction. These are:
- Returns a response describing the result of the action by looking it up on the interaction, possibly with a second subject
EITHER
- The subject of the action (inventory item, environmental item or character) changes it's description
EG. "punch wall" could change the wall's description to describe a dent in the wall
OR
- The subject of the action is replaced by another item
EG. "smash bottle" results in "bottle" changing to "broken bottle" or "kill John" results in the character John being replaced by environmental item "John's corpse".
- Returns a response describing the preceeding change
EG. "The broken pieces of the bottle are scattered across the floor."
- An area's description is changed.
EG. "smash lightbulb" results in the room's description changing to describe a pitch black room
- Items are added/removed from the inventory or the environment
EG. "pick up bottle". You now have a bottle in your inventory, and the bottle is removed from the environment.
- The directions available for movement and the areas which they lead to are changed
EG. "unlock door with key" allows you to move East into another room
- The player is moved to a new area
EG. "go north" takes you to another area.
I need to somehow determine in a generic way which of these consequences a particular Interaction should invoke, and invoke them. An action could potentially use a number of these consequences, or just one.
For example, if the item is a Bottle:
"fill bottle with water" would first return a response describing that you have filled the bottle with water. It would then replace the "bottle" item with a "bottle of water" item.
That is two consequences, returning a response and replacing an item.
Say you were then to do "throw bottle of water at window". This is more complex. It would first return a response describing the events that take place, the bottle and the window would both smash and water would go everywhere. The bottle would be removed from the Player's inventory.
Next, the "bottle of water" would be replaced by the "broken bottle" and the "Window" would be replaced with "Broken window". The area description would also change to reflect this.
That is five consequences, returning a response, removing an item from inventory, replacing two items and updating the description of the current area.
As you can see, I need a generic way of being able to define on a per "Interaction" basis, what the consequences of that action will be and update other objects such as Item, Player (for inventory) and Area appropriately.
I'm sorry if this is unclear, and I will do my best to clarify if anyone has any questions.
EDIT: Is there a way for me to define a method on an Interaction that I can pass a number of methods to call (and their parameters) into? The initial response returned would be the default, mandatory consequence, and then there could be extra ones if specified.
For example, in the examples above, for the first interaction, "fill with water", I would tell it to return a response ("You have filled the bottle with water") and also to call a ReplaceItem method that would replace the "bottle" subject with a "bottle of water".
For the second interaction I would tell it to return a response ("The bottle hurtles through the air into..."), call RemoveFromInventory on the subject of the action, call UpdateStatus on the bottle ("the bottle is smashed") and the window ("the window is smashed") and call UpdateAreaDescription to change the current area's description ("You are standing in a room with a single window, the glass smashed to pieces").
Does that sound feasible? I'm trying to keep this as generic as possible, for the sake of all the different possible interactions.
EDIT 2: To clarify further, and to attempt to summarize the problem:
In my game, there are Actionable objects (a bottle, a wall, John). Each Actionable object has a list of
Interaction objects which describe how a player can interact with them. At the moment, an Interaction has a
"Name" property ("throw", "hit", "break") and returns a Response ("You throw the ").
The issue that I am trying to resolve is that an Interaction also needs to do a number of other things, varying
by each particular Interaction. Let's take the example of a glass bottle.
"throw glass bottle"
- A response is returned ("You threw the glass bottle.")
- The "Bottle", is removed from the Player's inventory.
- The is replaced with a new to reflect the change. ("Bottle" replaced with "Broken bottle").
- A second response is returned ("The pieces of the glass bottle are scattered on the floor").
"throw glass bottle at window"
- A response is returned ("You threw the glass bottle at the window.")
- The object "Bottle", is removed from the Player's inventory.
- The object is replaced with a new object to reflect the change. ("Bottle" replaced with "Broken bottle").
- A second, optional object is replaced with a new to reflect the change. ("Window" replaced with "Broken window").
- The "Description" property of the current Area is updated. ("You are standing in a room, with a single broken window.").
When I create the Interactions, how can I vary the additional actions that they perform, such as status changes
to the subject, or changes to the current Area's description?
If you need more examples of actions as above, let me know and I'll do a few more.
I think you should decide on a set number of verbs you will recognize, and then for each object decide which of those verbs it is capable of responding to.
Lock Object Recognized Verbs
Look
UseItemOn(Key001, LockPicks, Sledgehammer, ...)
Punch
That way you can generically handle verbs it doesn't recognize with a response like "You can't <verb> the <object>, and handle verbs it does recognize with events or whatever.
Edit
As per your comment I obviously just scanned your question (too long for me). Still, I don't see the difference, really. The point is, an object participates in an event. From the Bottle's perspective, it gets hit by a wall. From the Wall's perspective, it gets hit by a Bottle. Both objects will have a list of verbs to which they will respond in a certain way.
So if you plan for the wall to be responsive to ANY thrown object, then you'll need to add a Collide verb to its list. You'll want to specify which objects it should care about colliding with, and maybe for each of those, how it should respond to particular magnitudes of force, etc.
But the principle is the same. For any event there are a number of participants, and each participant will have certain stimuli it cares about, and for those stimuli it will have certain stimulus origin objects it cares about. If it's a verb it cares about but its origin is not an object it cares about, then it will effectively ignore it - or respond in some vanilla fashion.
The Bottle participates in a Collision with the Wall. The Bottle has in its Verbs list the Collide interaction type. It may have a single object with which it cares about colliding, or it may have a value of Any, or AnySolid, or whatever. There's a million ways to architect that. In any case, the Wall also participates and may also have in its Verbs list the Collide interaction type. But it only cares about colliding with the Sledgehammer object - or maybe AnySolid that has a Mass of 10 or greater...
You could also do this with interfaces. You can have an LootableObject that implements ICollidible interface, or whatever. When any ICollidible (say, a bottle) executes its Collide method it will need certain parameters: how fragile it is, how much force it received, whether the colliding object is something it cares about, etc.
It may be full of liquid so it would implement an IContainer interface which has a Spill method, and also an IConsumeable interface which has a Drink method. It may be a lock which implements an ILockable interface which has an Unlock(obj Key) method and a Pick(int PickSkill) method. Each of these methods can produce certain changes in state to the object and the other particpant(s) in the interaction. You can do this with Events if you like.
Basically you need to decide what level of (un)predictability you want and then compose a matrix of interactions (not necessarily physics, but any kind of interaction you plan to operate on - a lockpicking event, a collision event, a drinking event) that involve certain predictable properties.
All actions you have described consist of the following:
A verb (for example "throw")
an object (for example "bottle")
an optional additional parameter describing the action further (for example "at window")
How about modelling each actionable object as a class derived from a common ancestor and have that class handle the action itself. Something like
public interface IObjectBase
{
bool HandleAction(string verb,string [] params)
}
public class Bottle: IObjectBase
{
bool HandleAction(string verb,string [] params)
{
//analyze verb and params to look for appropriate actions
//handle action and return true if a match has been found
}
}
You've got two things: the player and the environment (you might also have other players).
Pass them both to each interaction:
interaction.ActOn(environment, player);
//eg:
smash.ActOn(currentRoom, hero);
Then let each interaction work out what to do:
environment.ReplaceObject("window", new Window("This window is broken. Watch out for the glass!");
player.Inventory.RemoveObject("bottle");
player.Hears("The window smashes. There is glass all over the floor! If only John McLane were here...").
With the usual checks to make sure that the environment actually has a window, the player has the bottle, etc.
player.Inventory.ReplaceObject("bottle", new BottleOfWater());
Interaction then becomes a common interface which you can attach to anything in the system, be it an environment, player, bottle, etc. You can probably work out some particular types of interaction which you can use to remove duplication, but I'd start simple and go from there.
See also Double Dispatch.
Hah, I'm working on something similar too.
I'm wondering if your framework ends up becoming a text-adventure creator which is what my project is.
My approach is to have a sort of API that consists of methods that represent all the most basic actions in the game. Then use 'scripts', which are basically methods containing a combination of these basic actions.
These basic actions may involve:
Print a message
Change an object's/room's description
"Lock" or "unlock" an object. This means that "examine belt" will say "You don't seen any belt here" UNTIL "examine corpse" has been performed to learn that "The corpse has a shiny belt around its waist".
Lock or unlock exits from a room
Move the player to some room
Add/Remove something from the player's inventory
Set/Change some game variable eg. "movedGlowingRock = true" or "numBedroomVisits = 13" etc.
and so on... This is what I currently have in mind.
These are all methods in maybe an API class and take various parameters as necessary.
Now, there are rooms. Rooms have objects. Certain commands are valid for each object. One simple way is to have each room object hold a Dictionary of allowed commands. Script is a delegate that points to your action script. Ponder this:
delegate void Script();
class GameObject
{
public Dictionary<string, Script> Scripts {get; set;}
public string Name {get; set;}
//etc...
}
And your scripts, stored in the relevant Room instance:
//In my project, I plan to have such an abstract class, and since it is a game _creator_, the app will generate a C# file that contains derived types containing info that users will specify using a GUI Editor.
abstract class Room
{
protected Dictionary<string, GameObject> objects;
public GameObject GetObject(string objName) {...//get relevant object from dictionary}
}
class FrontYard : Room
{
public FrontYard()
{
GameObject bottle;
bottle.Name = "Bottle";
bottle.Scripts["FillWithWater"] = Room1_Fill_Bottle_With_Water;
bottle.Scripts["ThrowAtWindow"] = Room1_Throw_Bottle_At_Window;
//etc...
}
void void Room1_Fill_Bottle_With_Water()
{
API.Print("You fill the bottle with water from the pond");
API.SetVar("bottleFull", "true");
}
void Room1_Throw_Bottle_At_Window()
{
API.Print("With all your might, you hurl the bottle at the house's window");
API.RemoveFromInventory("bottle");
API.UnlockExit("north");
API.SetVar("windowBroken", "true");
//etc...
}
}
All this is sort of a skeleton view of what I have in mind (there are many subtleties I have noted, but this is good enough for an example). Sadly I haven't even coded a single word for my project, hehe. Everything on paper.
So...all this might give you some ideas to tinker with for your own project. If something is unclear, ask. Hope I haven't strayed from your question or something.
I think I spent too much time typing all this >_>
EDIT:
PS: My skeleton example doesn't exactly show how to manage commands involving multiple game objects (This is just one of the many subtleties I hinted at). For stuff like "throw bottle at window", you need to think up how to manage such syntax, eg. a taste of my solution to this is to parse and discover what command is being issued... "throw GO at GO". Find out what the game objects are, then see if the current room has them. etc etc.
More importantly, this also prevents you from holding scripts inside a game object instance, since one command involves more than one game object. Probably better to store the Dictionary in the Room instance now.
(This is sort of where I am with my project.)
Pardon my ramblings... >_>
It seems like your issue is managing propagation of events. Microsoft handles this issue (for less colorful purposes) using the Observer pattern/events.
I think the combining the Observer and Mediator design patterns from Gamma,etc.'s book "Design Patterns" would be very helpful for you. The book has a sample ChangeManager class that might be helpful, but I have attached some other links that should serve you well.
One implementation suggestion I have would be to use a static or singleton class that acts as the mediator and also stores references to all of the actionable objects in active memory as well as all of the invoked actions. This class can process the algorithms to determine all of the responses and the chronological order of the responses from a given action. (If you consider that the collateral-effects of a primary action, A, can affect the consequences of that action, A, prior to the action completing, it would become evident that the proper chronological sequence is necessary, and must update before invoking each collateral action.)
Microsoft's article on the observer pattern: http://msdn.microsoft.com/en-us/library/ee817669.aspx
DoFactory on Mediator pattern (with UML diagrams): http://www.dofactory.com/Patterns/PatternMediator.aspx
DoFactory on Observer pattern (with UML diagrams): http://www.dofactory.com/Patterns/PatternObserver.aspx
IObserver interface documentation in .Net 4,
http://msdn.microsoft.com/en-us/library/dd783449.aspx
another article on the observer pattern. http://www.devx.com/cplus/Article/28013/1954
Interaction can be defined as "Verb + {List of Filters} + {List of Responses}"
For your "fill bottle with water" example, the Interaction would be:
Verb: Fill({"fill", "pour"})
List of Filters: Have(player, "bottle"), Have(currentRoom, "water tap")
List of Responses: Print("You filled the bottle with water"), Remove(player, "bottle"), Add(player, "bottle of water")
alternatively, List of Responses can be: SetAttribute(player.findInventory("bottle"), "fill", "water")
Then if you need to "throw bottle of water at windows":
Verb: Throw({"throw", "smash"})
List of Filters: Have(player, "bottle of water"), Have(currentRoom, "windows")
List of Responses: Print("The bottle smashed with the windows, and both of them are broken"), Remove(player, "bottle of water"), Add(curentRoom, "broken bottle"), Remove(currentRoom, "window"), Add(currentRoom, "broken window"), SetAttribute(currentRoom, "description", "There is water on the floor")
Upon entering a Room, the Framework will query all objects in the room for a list of valid Verbs, and enumerate them. When the player enters a command, the framework searches for a Verb that matches the command; then it will check the list of Filters, and if all of them is True, then iterate through the List of Responses to execute them in order.
The Responses would be a function object which implements the IResponse interface which has some constructors, and a IResponse.do() method. The Filters will be function object which implements the IFilter interface, again with some constructors, and IFilter.check() method returning a boolean. You can even have And(), Or(), and Not() filter to make more complex queries.
You can make things even more readable by having some convenience methods, a Player could have Player.have(Actionable) convenience method so you can write player.have("bottle of water"), which returns not the bottle object itself, but an IFilter object that will check whether the player have "bottle of water" when its .check() method is called. Basically, make the objects lazy.
Alright guys, here's how I handled it. It was the most generic way I could think of and I think it suits what I am trying to achieve.
I added an "Invoke()" method to the Interaction class, a new Interface called IActionResult which defined an "Initiate()" method, and a number of different ActionResult types for each possible consequence. I also added a List of ActionResults to an Interaction. The Invoke method would simply loop through all of the IActionResult objects and call the Initiate() method.
When you define an Interaction on an item, you would pass in a list of verbs for that Interaction and then add a number of ActionResult objects depending on the consequences of that Interaction.
I also added a GlobalActionReference, which would be updated each time an action is performed, and an ActionResult would have appropriate access to the objects it needs to update through this.
I really appreciate all of your suggestions, and I'm sorry if I wasn't clear with my question or my comments (or even this answer). Thanks for your help.
Whenever i feel hungry i will publish i am hungry.This will be notified to the service providers say (MealsService,FruitService,JuiceService ).(These service providers know what to serve).
But the serving priority is the concern. Priority here means my first choice is MealsService when there are enough meal is available my need is end with MealsService.To verify the enough meal is availabe the MealsService raises the event "updateMeTheStockStatus" to the "MealsServiceStockUpdateListener" .
The "MealsServiceStockUpdateListener" will only reply back to "MealsService" . No other Service providers ( FruitService,JuiceService ) will be notified by the "MealsServiceStockUpdateListener" .If there is no sufficient stock then only the MealsService passes notification to the JuiceService (as it is the second priority).As usual it checks the stock.If stock is not sufficient it passes message to FruitService,so the flow continues like this.
How can i technically implement this?
Any implemention like priority based delagates and delegate chaining make sense ?
(Somebody! Please reframe it for good readability ).
Update : In this model there is no direct communication between "StackUpdateListener" and "me".Only The "Service Providers" will communicate me.
Like other answerers, I'm not entirely convinced that an event is the way forward, but let's go along with it for the moment.
It seems to me that the business with the MealsServiceStockUpdateListener is a red herring really - you're just trying to execute some event handlers but not others. This sort of thing crops up elsewhere when you have a "BeforeXXX" event which allows cancellation, or perhaps some sort of exception handling event.
Basically you need to get at each of your handlers separately. There are two different ways of doing that - either you can use a normal multicast delegate and call GetInvocationList() or you can change your event declaration to explicitly keep a list of handlers:
private List<EventHandler> handlers = new List<EventHandler>();
public event EventHandler MealRequired
{
add { handlers.Add(value); }
remove
{
int index = handlers.LastIndexOf(value);
if (index != -1)
{
handlers.RemoveAt(index);
}
}
}
These two approaches are not quite equivalent - if you subscribe with a delegate instance which is already a compound delegate, GetInvocationList will flatten it but the List approach won't. I'd probably go with GetInvocationList myself.
Now, the second issue is how to detect when the meal has provided. Again, there are two approaches. The first is to use the normal event handler pattern, making the EventArgs subclass in question mutable. This is the approach that HandledEventArgs takes. The second is to break the normal event pattern, and use a delegate that returns a value which can be used to indicate success or failure (and possibly other information). This is the approach that ResolveEventHandler takes. Either way, you execute the delegates in turn until one of them satistfies your requirements. Here's a short example (not using events per se, but using a compound delegate):
using System;
public class Test
{
static void Main(string[] args)
{
Func<bool> x = FirstProvider;
x += SecondProvider;
x += ThirdProvider;
Execute(x);
}
static void Execute(Func<bool> providers)
{
foreach (Func<bool> provider in providers.GetInvocationList())
{
if (provider())
{
Console.WriteLine("Done!");
return;
}
}
Console.WriteLine("No provider succeeded");
}
static bool FirstProvider()
{
Console.WriteLine("First provider returning false");
return false;
}
static bool SecondProvider()
{
Console.WriteLine("Second provider returning true");
return true;
}
static bool ThirdProvider()
{
Console.WriteLine("Third provider returning false");
return false;
}
}
Rather than publish a message "I'm hungry" to the providers, publish "I need to know current stock available". Then listen until you have enough information to make a request to the correct food service for what you need. This way the logic of what-makes-me-full is not spread amongst the food services... It seems cleaner to me.
Message passing isn't baked into .NET directly, you need to implement your own message forwarding by hand. Fortunately, the "chain of responsiblity design pattern" is designed specifically for the problem you're trying to solve, namely forwarding a message down a chain until someone can handle it.
Useful resources:
Chain of Responsibility on Wikipedia
C# implementation on DoFactory.com
I'm not sure if you really need a priority event. Anyways, let's suppose we want to code that just for fun.
The .NET Framework has no support for such a peculiar construct. Let me show one possible approach to implement it.
The first step would be to create custom store for event delegates (like described here);
Internally, the custom event store could work like a priority queue;
The specific EventArgs used would be HandledEventArgs (or a subclass of it). This would allow the event provider to stop calling handlers after one of them sets the event as Handled;
The next step is the hardest. How to say to tell the event provider what is the priority of the event handler that is being added?
Let me clarify the problem. Usually, the adding of a handler is like this:
eater.GotHungry += mealsService.Someone_GotHungry;
eater.GotHungry += juiceService.Someone_GotHungry;
eater.GotHungry += fruitService.Someone_GotHungry;
The += operator will only receive an delegate. It's not possible to pass a second priority parameter. There might be several possible solutions for this problem. One would be to define the priority in a custom attribute set at the event handler method. A scond approach is discussed in the question.
Compared to the chain of responsibility implementation at dofactory.com, this approach has some advantages. First, the handlers (your food services) do not need to know each other. Also, handlers can be added and remove at any time dynamically. Of course, you could implement a variation of a chain of responsibility that has this advantages too.
I don't think delegates are the proper solution to your problem. Delegates are a low-level service provided by C# for relatively tightly coupled events between components. If I understand your question properly (It is worded a little oddly, so I am not sure I clearly understand your problem), then I think what you need is a mediated consumer/provider.
Rather than having your consumers directly consume the meal, juice, and fruit providers, have them request a food item from a central mediator. The mediator would then be responsible for determining what is available and what should be provided to the consumer. The mediator would be a subscriber to events published by all three services. Whenever stock is added/updated in the Meal, Juice, or Fruit services, they would publish their current stock to all subscribers. The mediator, being a subscriber, would track current stock reductions on its own, and be able to determine for itself whether to send a meal, juice, or fruit to a food consumer when a get food request is made.
For example:
|---------- (GetFoodResponse) ----------------
V |
FoodConsumer ---- (GetFoodRequest) ------> FoodProvider <-----> [ Local Stock Data ]
^
|
|
MealService ---- (PublishStockMessage) ----------|
^
JuiceService --- (PublishStockMessage) ----------|
^
FruitService --- (PublishStockMessage) ----------|
The benefits of such a solution are that you reduce coupling, properly segregate responsibility, and solve your problem. For one, your consumers only need to consume a single service...the FoodProvider. The FoodProvider subscribes to publications from the other three services, and is responsible for determining what food to provide to a consumer. The three food services are not responsible for anything related to the hunger of your food consumers, they are only responsible for providing food and tracking the stock of the food they provide. You also gain the ability to distribute the various components. Your consumers, the food provider, and each of the three food services can all be hosted on different physical machines if required.
However, to achieve the above benefits, your solution becomes more complex. You have more parts, and they need to be connected to each other properly. You have to publish and subscribe to messages, which requires some kind of supporting infrastructure (WCF, MSMQ, some third party ESB, custom solution, etc.) You also have duplication of data, since the food provider tracks stock on its own in addition to each of the food services, which could lead to discontinuity in available stock. This can be mitigated if you manage stock updated properly, but that would also increase complexity.
If you can handle the additional complexity, ultimately, a solution like this would more flexible and adaptable than a more tightly connected solution that uses components and C# events in a local-deployment-only scenario (as in your original example.)
I am having a bit of trouble understanding your analogy here, which sounds like you're obscuring the actual intent of the software, but I think I have done something like what you are describing.
In my case the software was telemarketing software and each of the telemarketers had a calling queue. When that queue raises the event signifying that it is nearing empty, the program will grab a list of available people to call, and then pass them through a chain of responsibility which pushes the available call into the telemarketer's queue like so:
Each element in the chain acts as a priority filter: the first link in the chain will grab all of the people who have never been called before, and if it finishes (ie. went through all of the people who have never been called) without filling up the queue, it will pass the remaining list of people to call to the next link in the chain - which will apply another filter/search. This continues until the last link in the chain which just fires off an e-mail to an administrator indicating that there are no available people to be called and a human needs to intervene quickly before the telemarketers have no work to do.