Most Read This Week
Build a Simple Mach-II Application
Build a Simple Mach-II Application
By: Hal Helms
Oct. 15, 2003 12:00 AM
In the August edition of CFDJ, Ben Edwards and I presented a first look at Mach-II, a new, object-oriented framework for building software applications. In this issue, I offer a tutorial (with commentary) on building a simple Mach-II application.
My choice of subjects for our Mach-II application may have been influenced by spending the last two and a half weeks in Las Vegas training students on Java, Mach-II, and Fusebox 4, culminating in the Fusebox conference. What inspired me for the application was watching otherwise intelligent people trying to outdo each other in throwing away money. Blackjack and poker, I understand; there the player does have some possible positive expectation, but craps and roulette? Watching players eagerly give up 5% or more to the house – with predictable results – I decided that the new Las Vegas slogan, "What happens here stays here," should be amended to "What you bring here stays here."
In this Mach-II application, we'll build a roulette game. While our game is admittedly not as much fun as the real thing, it has the distinct advantage that you can cheat to make yourself a winner without risking a late-night meeting with someone named "Vinny."
Let's start by quickly reviewing key Mach-II concepts. The architecture of Mach-II is known as event-based, implicit invocation. Each request to the framework spawns an event, an encapsulation of the request that includes such things as form and URL variables. The system then looks for software components known as listeners that are registered at configuration as listening for certain events. At configuration time, the system architect registers the listener, the way the listener should be called (using an invoker), and the method to be called. The framework itself knows nothing about what the listeners are up to, nor does any listener correspond with any other. The system is said to be highly cohesive (listeners have a highly focused mission) and loosely coupled (listeners are unaware of each other).
To determine the events the system needs, let's create a narrative that describes the roulette system. It might look something like this:
A player logs into the system, providing his or her name and starting balance. The player is then shown a roulette table from which to select numbers to bet on and an amount to be bet on each number.When the betting is done, the wheel is spun and the dealer pays off any winning bets according to the traditional American-style odds.
Since there are 38 numbers on an American wheel (the integers 1–36 accompanied by a zero and a doublezero), the true odds on any number being chosen are 38:1. The payoff, however, is only 35:1. The house edge is therefore 5.26%. If this doesn't seem too onerous, consider that the 5% edge is not on the bankroll, but on the action. Action is defined as the total amount risked: each new time "through" the bankroll represents that much more action. A $100 bankroll can easily generate $1000–2000 in action. Take 5% of that action and you can see why Las Vegas can afford to air-condition the desert, provide free drinks, and put on some nifty entertainment. (Several years ago, a casino executive was asked by a talkshow host what the casino did with "system players" – people who had developed a system whereby they thought they could beat the house odds. The executive's response? "We send a limo to the airport to pick them up.")
What events can we discover from our narrative? The ones I've identified are shown below in Table 1:
Why is there no event for WheelSpin, PlayerWins, or PlayerLoses? Understanding this is key to understanding event-based systems in which not all actions are events and not all components are listeners.
Consider that an object-oriented application is made up of many components that comprise an object model. The object model identifies the components with their associated methods that form a scale model of the system under study. The object model should be independent of the application using it.
If you're familiar with the Unified Modeling Language (UML), you'll recognize that the object model is presented in the form of a class diagram. While CFCs aren't strictly classes, they exhibit many similarities, so much so that a class diagram can be of great benefit. There are many excellent UML modeling tools available, but for our purposes we recommend the excellent Web-based gModeler created by Grant Skinner and built on Flash (www.gModeler.com).
What components and what methods do we need for roulette? Answering this question goes to the heart of how you choose to model the portion of the world under study. There are no right/wrong answers here, only better or worse judgments. The ones I've used for our sample application are shown in Figure 1.
All components are modeled as CFCs. The RouletteTable CFC is the key component; three of the other four components relate to it through the mechanism of composition, also known as "has-a" relationship – as in "a RouletteTable has a History." The other component, BankAccount, also relates to the Person CFC through composition. (For more on class relationships, see my book, Discovering CFCs, from techspedition.com.)
These CFCs can and should be built independently of our Mach-II application. We can create test scripts to ensure that each component is doing its job properly. For example, an extremely simple (and inadequate) test script to see that RouletteTable's generateWinningNumber() is working properly might look like this:
<cfset table = CreateObject('component',
When we're done, we should have a working, consistent model of a roulette game. We don't, though, have an application. For that, we turn to Mach-II. We need to find a way "into" our object model. This is accomplished by having a system component act as a listener for application events. The RouletteTable is an ideal candidate for a listener, since all other components relate directly or indirectly to it.
With our events and our listener determined, it's time to create the view pages that the player will see. There are only two: the initial player login page and the roulette table itself (see Figures 2 and 3).
Since roulette players (like many gamblers) have a poor concept of odds, the house indulges their fantasy by showing previous winning numbers so that players can judge which numbers are "due." After several plays, the "Previous winners" section of the table is populated (see Figure 4).
With the scale model built and the view pages created (the code for this application can be downloaded from www.mach-ii.com), we're ready to tie everything together.
Start by creating a roulette directory structure under your webroot that looks like that shown in Figure 5.
The model directory should house all of the CFCs shown in our class diagram. The views directory should hold the two view pages identified. If you recognize the terms, model and view, from the Model-View-Controller design pattern, you may be wondering where the controller directory is. In Mach-II, the framework itself is the controller.
The configuration of the system is the work of mach-ii.xml, found in the config directory. For this article, I show only the germane sections of the file dealing with events and listeners (see Listing 1).
The only listener specified is rouletteTable, which is invoked using a built-in Mach-II invoker, MachII.framework. invokers.CFCInvoker_EventArgs. While we don't have space to go into invokers, we can say that this invoker will turn all URL and form variables into a structure that is then passed to the listener. The <event-handlers> section holds individual <event-handler> elements. Each event-handler defines an event and the listeners and/or views that are affected by it.
At runtime, player requests trigger events. The Mach-II framework reacts to these events, calling the prescribed method for each listener in the order in which each was registered, passing a reference to the event to the affected listener. Listeners can return information to the system through the resultKey attribute of the event-handler. This variable can then be read by the view pages.
Events and listeners can themselves announce new events. We can see that the settlement event announces a showTable event. When you examine the full code, you can find listeners (CFCs) that also announce events.
Events can be provided with event mappings. Since listeners are part of the object model and since many applications may be served by a single object model, there is no assurance that events announced by listeners will match the event handlers shown in the application. In order to provide as loose a coupling between components as possible, the event-mapping element maps events announced by listeners to events present in the application's configuration file. This sort of flexibility is a hallmark of Mach-II with its reliance on ease of application maintainability.
To fully understand the roulette application, download and study the code from www.mach-ii.com. Whether Mach-II fits your application framework needs is, of course, something you must decide. But if flexibility and maintainability are important goals of your system, Mach-II is definitely worth your consideration.
Reader Feedback: Page 1 of 1
Subscribe to the World's Most Powerful Newsletters
Today's Top Reads