Page 16 - MSDN Magazine, June 2019
P. 16
The Working Programmer TED NEWARD Coding Naked: Naked Acting
Welcome back, NOFers. Last time, I examined how NakedObjects handles collections, which provide the ability to associate a number of objects with one another (msdn.com/magazine/mt833439). As I went through that piece, however, I introduced the concept of an “action” into the code without really explaining it in any detail. Because actions are the “code” pairing to properties’ “data,” it makes sense to go over actions in a bit more detail—and in particular, note the places where actions can live and how they appear in the UI.
Ready to act naked?
Actions
The NOF manual describes an action as “a method that is intended to be invoked by a user.” It’s important to note, though, that these methods aren’t just user-invokable; the manual goes on, in the same sentence, to point out that “it may also be invoked programmatically from within another method or another object.” Actions, then, are where behavior on an object is defined, and NOF will generate a menu item for the user to click/invoke for each action it discovers.
Actions, then, are where behavior on an object is defined, and NOF will generate a menu item for the user to click/invoke for each action it discovers.
One such action that easily comes to mind is the idea of per- forming the basic CRUD behaviors on a given Talk (or Speaker, for that matter), but recall that NOF already handles those as part of the core behavior of the UI as a whole. A menu item off the main menu allows you to create a new Speaker, which, remember, is defined on the SpeakerRepository, as you saw in the second article in this series (msdn.com/magazine/mt833268). Editing that speaker happens after a Speaker is selected and the user selects the “Edit” menu item that appears. In fact, the only thing missing from the list is the ability to delete a Speaker, so that’s an easy place to start—I’ll now add an Action that allows me to delete the currently visible Speaker.
(I know, I know—who would ever want to delete a Speaker? We’re all so lovable, it’s hard to imagine that anyone would ever
want to remove a Speaker from the system. But go with me on this one, for pedagogical purposes if nothing else. Imagine they’re retiring. Or something.)
To add a new action, I only need to add a new method to the Speaker type. By default, any public method on a domain object will be exposed as an action in the “Actions” menu of the UI, so adding this is pretty straightforward:
public void Delete() {
Container.DisposeInstance(this); }
Recall that the Container property is an instance of the IDomain- ObjectContainer that’s dependency injected onto each Speaker after it’s created or returned from the SpeakerRepository. To remove a persisted object (such as a Speaker that was added with the CreateNewSpeaker action on the SpeakerRepository), the Container has to “dispose” of that instance.
However, when I add this to the Speaker class and run it, some- thing bad happens—specifically, after deleting the Speaker, I get an error about a missing object. The NOF client is complaining that the domain object it was just displaying—the Speaker that was just deleted—no longer exists. That makes a ton of real sense, when you think about it, and the answer is to give the UI something else to display, such as the list of all the remaining Speakers in the system, which I can get easily enough from the Container again, like so:
public IQueryable<Speaker> Delete() {
Container.DisposeInstance(this);
return Container.Instances<Speaker>(); }
Now, when the user selects to delete a Speaker, the UI removes them, shows the remainder of the list of Speakers, and life moves on. (Farewell, sweet Speaker. We remember you fondly.)
One problem that emerges, however, is that certain domain objects have a clear dependency on others within the system, and arbitrarily destroying those objects without thinking about those associations will sow chaos. (In fact, NOF will prevent deletion of an object that has any associated objects until those associated objects are deleted first.) In practical terms, this means if the Speaker has any Talks cre- ated, deleting the Speaker will leave those Talks orphaned. Ideally, you wouldn’t allow Speakers who have one or more Talks created to be deleted. You could put a check inside the Delete method, and provide an error message if the user selects it and you can’t follow through, but it’s generally a better idea to disallow a user the option of even selecting something they’re not allowed to do—in NOF parlance, you want to disable the action entirely.
12 msdn magazine