public abstract class AbstractResource { abstract protected begin(ResourceClient client, Object object); abstract protected end(ResourceClient client, Object object);-PatrickLoganpublic void consume(ResourceClient client, Object object) { begin(client, object); try { client.consume(this, object); } finally { end(client, object); } } }
public interface ResourceClient { abstract public void consume( AbstractResource resource, Object object ); }
But what if an object needs to own a resource for longer than the duration of a single method call? Would the AbstractSessionPattern (http://www-dse.doc.ic.ac.uk/~np2/patterns) help here?
Even in an event-driven situation, there's usually some state, somewhere, that corresponds to the life of the object. The method in question might just look like
[self finished] whileFalse: [self waitSeconds: 30]while all kinds of other objects are playing with the resource this guy controls.
Why isn't the begin() inside the try block? --BobPasker
It's outside for flexibility, I believe. I as the framework user get to decide whether I want all my initialization to occur inside or outside the try{}. For example, I may want to open a file in begin(), knowing that since I'm outside the try{} block at that point, my end() implementation won't be called, and therefore my end() implementation won't have to handle an unopened file. Or, if that doesn't meet my needs, I could simply have an empty begin(), and put all my initialization inside ResourceClient.consume (see below for my feelings on the method names). -- DavidSaff
This is a great idiom, Patrick. It almost fully fills the void left by ResourceAcquisitionIsInitialization. But given the new idiom, the old "consume" metaphor seems out of place, since it feels like the client is entering the resource, rather than acquiring the resource. I'd be tempted to replace it with a feel similar to the VisitorPattern (is this a misuse of that pattern? The current problem doesn't deal with forces arising from a complex data structure.)
public abstract class AbstractResource { abstract protected welcome(ResourceVisitor? visitor, Object baggage); abstract protected farewell(ResourceVisitor? visitor, Object baggage);Two issues with this:public void accept(ResourceVisitor? visitor, Object baggage) { welcome(visitor, baggage); try { visitor.visitResource(this, baggage); } finally { farewell(visitor, baggage); } } }
public interface ResourceVisitor? { abstract public void visitResource( AbstractResource resource, Object baggage); }
One other aspect that I can't quite resolve. What if a given client needs to consume (or visit) more than one resource at a time to accomplish its task? Is it desirable or possible to package a given set of resources as a single "meta-resource", or is there some other idiom for this? Say I need a database Connection resource and a remote procedure call? Ignoring for the moment any two-phase commit semantics -- maybe the RPC is simply an audit log. How does this idiom adapt to that situation? --StevenNewton
The RubyLanguage libraries use this idiom very widely. The idiom is much more convenient when you have a decent syntax for closures. I expect that Java's inner classes are too verbose and obfuscatory to allow this idiom to catch on, and people will stick with try...finally blocks.
This page mirrored in JavaIdioms as of April 29, 2006