On Mar 25, 2:41 am, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
THIS.org> wrote:
> > I thought that it might be annoying to write stuff like:
> > synchronized(target) { target.doOp(); target.doOp2(); }
[quoted text clipped - 53 lines]
> separation of the 'target' and 'sync' objects in the wrapper API is intended to
> be a step in that direction).
All of those are good points.
A little more background for my particular project might help.
I have a class "Game", which contains at least one member of type
"GameState". GameState is an abstract class, implementing the "State/
Strategy" pattern. Certain method calls are only valid with certain
states. The actual value of the GameState object depends on the valid
operations on Game.
So, here comes the synchronizing design...
Operations on Game need to be atomic, and Game is already large enough
that I'd prefer not to delegate to GameState within game. I created a
facade class "GameController" which references a "Game" object. There
can be several GameController objects per Game object. GameController
delegates to a few methods in Game, and then all methods in
game.getGameState(). I am asserting that each method on
GameController needs to be atomic to the given Game object. Hence the
target/sync in my proxy.
My target would the GameController, and my sync would be the Game.
This allows the GameController to behave correctly even if there are
more than one acting on the same Game.
I realized that my code would have to be constructed with the concept
that the method call itself was the atomic operation, not a group of
them. This is knowledge that is important anyway, so if someone
doesn't understand this, then they are likely to write incorrect code
with and without my proxy, I think.
To put it another way. my GameController only exposes methods which
are transactional. It is also only invoked by a user performing an
action in a GUI. The operations themselves are fast enough, and
spread far enough apart, that the synchronization isn't going to harm
performance, and is actually required for proper operation.
On Mar 25, 2:41 am, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
THIS.org> wrote:
> The only case I can think of (so far) where the automatic synchronised wrappers
> might be worthwhile is if the wrapper is /only/ intended to protect the state
> of the network proxy object itself, not the state of the object it is a proxy
> /for/. (In which case method-level boundaries would be appropriate -- but then
> I'd sort of hope the RMI implementation would have that under control anyway).
Actually, I think you've got this backwards...
The GameController would be proxied to a threadSafeGame. The
threadSafeGame object stays on the server side, and then a
gameControllerRemoteStub is sent to the Client side... The Stub is
actually a proxy for the threadSafeGame, and the threadSafeGame a
proxy for the gameController. Calls on the client side may be serial,
but they might be parallel as well. the threadSafeGame makes them all
serial with regards to the game object.
Does this design make more sense? Or do you still think its an
antipattern?
Chris Uppal - 27 Mar 2007 06:57 GMT
> I have a class "Game", which contains at least one member of type
> "GameState". GameState is an abstract class, implementing the "State/
> Strategy" pattern. Certain method calls are only valid with certain
> states. The actual value of the GameState object depends on the valid
> operations on Game.
OK. That makes sense.
> I created a
> facade class "GameController" which references a "Game" object. There
> can be several GameController objects per Game object. GameController
> delegates to a few methods in Game, and then all methods in
> game.getGameState().
If GameController is talking directly to the GameState then your design is not,
after all, a variant on the State pattern (or Strategy, come to that), and I no
longer feel I understand what the design is. That's not to suggest that
there's anything wrong with the design, but take my remaining comments with
corresponding caution.
> To put it another way. my GameController only exposes methods which
> are transactional. It is also only invoked by a user performing an
> action in a GUI. The operations themselves are fast enough, and
> spread far enough apart, that the synchronization isn't going to harm
> performance, and is actually required for proper operation.
It sounds as if you GameController has responsibility for grouping primitive
operations on Game into semantically/transactionally atomic units. If so, then
I question whether it's appropriate to hide that -- critical -- aspect of its
function in the implicit synchronisation provided by a SynchronisingWrapper
/around/ a GameController.
> Does this design make more sense? Or do you still think its an
> antipattern?
Let me put it this way: I'm /less/ skeptical now ;-)
-- chris
Daniel Pitts - 27 Mar 2007 20:19 GMT
On Mar 26, 10:57 pm, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
THIS.org> wrote:
> > I have a class "Game", which contains at least one member of type
> > "GameState". GameState is an abstract class, implementing the "State/
[quoted text clipped - 34 lines]
>
> -- chris
:-)
Okay, let me try to clarify the design further...
The Game object contains a method GameState getState().
GameControllerImpl has a reference to a Game object. each method on
GameController either calls a method on Game, or a method on
game.getState(). Calling, say, game.getState().deal() CAN change the
current GameState object referenced in Game. So, by synchronizing
against the Game object, I protect the game's state, as well as the
game's gameState reference.
The GameController interface is ALSO used as an RMI interface/GUI
facade.
Thats why I say I use the State pattern. The behaviour of the object
returned by game.getState() is likely different every time.
Esmond Pitt - 27 Mar 2007 08:48 GMT
Is there a reason why you don't just make all the GameController methods
synchronized? as they have to be atomic?
Chris Uppal - 27 Mar 2007 09:29 GMT
> Is there a reason why you don't just make all the GameController methods
> synchronized? as they have to be atomic?
AIUI, they have to be atomic with respect to their common Game object, so just
tagging their methods' declarations with 'synchronized' wouldn't do the trick.
-- chris