|
From: Karsten Wutzke on 10 Jan 2008 09:59 Hello all! Be warned, this is a practical question... ;-) Some time ago I've had some discussions about the Proxy pattern to apply to implementing the client side of a chat application. After I decided upon a solution, I felt the Proxy pattern is a somewhat strange pattern. I never really grasped the purpose of a remote chat (channel) proxy. Basically it is just a stupid object from some subclass representing what is stored and happening on a chat server. From an abstract point of view one or more instances are needed to basically accomplish two things: 1. Receive messages from the server and translate those into an MVC style model object which needs to update itself and notify the GUI appropriately. This would serve as an *incoming* messages interface. 2. From the GUI itself, the locally logged in user can issue commands of some kind, e.g. "join chat", "send message", "kick user", "create new chat" etc. This is the *outgoing* messages component. What I did was to create a simple chat interface modeling one command per method (interface Chat): public boolean join(User usr); //add public boolean part(User usr); //remove public boolean send(User usrSender, String strMessage); public boolean kick(User usrKicker, User[] usrKickeds); ... The chat server class with the thread waiting for messages to arrive (class ChatServer implements Runnable) parses the message and sets the chat model's properties ("send message" on a model class). The model class extends some Observable class (class ChatModel extends Observable implements Chat), which is somewhat typical for model objects (incoming part). I created another chat class (class ChatProxy implements Chat) for the outgoing part. Both incoming model interface and outgoing proxy interface share the same interface. The getter methods simply delegate to the model object so that the very latest actual model properties can be retrieved. ----------------- * 1 ----------------- | Chat |<----------------------| ChatServer | ----------------- ----------------- ^ | ------------+------------ | | ----------------- ----------------- | ChatModel |<------| ChatProxy | ----------------- ----------------- I'm very unsure if I understood the proxy pattern right here... creating the model class seemed perfect as I do so in every program. The proxy (as interpreted by myself above) delegates all getters to the model and only has outgoing implementations differing from the model. The implementation of kickUser on the model actually tries to find the user in the chat's user list and removes that user if found, the implementation of kickUser on the proxy class generates a server message and puts some server specific byte stream on a socket. As I said, I'm unsure about the implementation, it seems quite complicated. I could as well merge the two subclasses and create two different sets of methods in that class, one that basically handles incoming messages like "removeUser" after a kick and one method kickUser that obviously generates an outgoing message... I guess both approaches basically work, I just can't figure out why I really chose the former. I'd like to get some input on what is the better approach and why. Maybe there's a third or fourth, anway I'd like to get some opinions on that. TIA Karsten PS: The exmples above are Java centric
From: H. S. Lahman on 10 Jan 2008 11:20 Responding to Wutzke... > From an abstract point of view one or more instances are needed to > basically accomplish two things: > > 1. Receive messages from the server and translate those into an MVC > style model object which needs to update itself and notify the GUI > appropriately. This would serve as an *incoming* messages interface. > > 2. From the GUI itself, the locally logged in user can issue commands > of some kind, e.g. "join chat", "send message", "kick user", "create > new chat" etc. This is the *outgoing* messages component. > > What I did was to create a simple chat interface modeling one command > per method (interface Chat): > > public boolean join(User usr); //add > public boolean part(User usr); //remove > public boolean send(User usrSender, String strMessage); > public boolean kick(User usrKicker, User[] usrKickeds); > ... > > The chat server class with the thread waiting for messages to arrive > (class ChatServer implements Runnable) parses the message and sets the > chat model's properties ("send message" on a model class). The model > class extends some Observable class (class ChatModel extends > Observable implements Chat), which is somewhat typical for model > objects (incoming part). I created another chat class (class ChatProxy > implements Chat) for the outgoing part. Both incoming model interface > and outgoing proxy interface share the same interface. The getter > methods simply delegate to the model object so that the very latest > actual model properties can be retrieved. Does either the GUI or the chat server care about different threads in the client for managing different chats simultaneously? No. That's why a proxy comes in handy. It hides such details from the clients -- in both directions. It probably also acts as a kind of Observer for the GUI that converts server chat identity into GUI identity (i.e., it knows how to convert server messages into chat window handles or something else the GUI layer cares about). My pushback is twofold. It seems to me that the thing requiring a proxy is the server rather than the chat. That's where you need to make identity and thread mapping decisions. In that case the proxy would be two-way as it addressed messages properly to both MVC model instances and the server(s). I would see the MVC object as a dumb data holder that was basically a pass-through for messages to/from the GUI. (There would be a 1:1 correspondence between GUI chat window instances and MVC Chat instances.) IOW, the GUI object has the rendering smarts for draw() while the server proxy has the smarts for keeping track of who is talking to whom and ensuring they don't step on one another. BTW, in the Proxy pattern note that the client is always talking to the proxy instance. The proxy subclass instance then talks to the actual subject instance. This allows the proxy to insert additional <hidden> housekeeping behaviors into the responsibility that the client thinks it is invoking. To that extent the GoF structure representation is misleading because it implies that the Client could be related directly to a RealSubject instance. That's possible if there are other, unaugmented RealSubject responsibilities that could be accessed directly by the client. However, it would require a lot of care because one would have to ensure that when the augmented responsibilities were needed the relationship is not instantiated to a RealSubject. So in practice the relationship between Client and Subject is almost always instantiated only at the Proxy subclass level rather then the Subject superclass. -- There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)pathfindermda.com Pathfinder Solutions http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman "Model-Based Translation: The Next Step in Agile Development". Email info(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH
|
Pages: 1 Prev: Two Active Interface Next: Why is Object Oriented so successfull |