GeeCON Prague 2014*
The moose likes Java in General and the fly likes designing for multiple layers Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Java » Java in General
Bookmark "designing for multiple layers" Watch "designing for multiple layers" New topic
Author

designing for multiple layers

Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Here is a problem I have run into several times.

I start with one object . Lets call that Object A.
Object A needs to instantiate a large number of other objects, one of which is B.
B in turn makes C, which needs a D, and maybe D makes E.

To make things concrete, suppose that A is a FrameView class of your standard Swing application and that it describes most of the user interface (GUI) of a single frame application. B and C are classes that describe different kinds of widgets, and D and E are classes that act on those widgets. And lets further say that E is a SwingWorker that does a long computation that needs to post updates to the GUI.

The difficulty is that E, would now need a reference to A's progress bar (or some other Swing Component on the user interface). Now the obvious (somewhat inelegant) way of handling this would be fore A to pass a reference to that component to B, and for B to pass that on to C, who passes it on to D who delivers it finally to E. But if B,C, and D, don't use that component at all (remember these are just classes that describe widgets and therefor don't really have any user interface functionality) then it seems really awkward to include this reference in all the constructors.

In a less OO environment, I could just make myself a global variable pointing to the progress bar. I am not saying that is a good OO technique but in Java I don't seem to have that option if I wanted to use it.

Another approach would be to have E create its own progress bar. But how would I do placement? I couldn't be sure the user had not moved the Window of the main Gui, and I don't know where that main window is because I don't have a reference. For the particular issue of a progress bar I may not care about placement but this is an example of a bigger problem, which I can now sum as follows.

How does an object at the top of a large hierarchy of objects, inform objects near the bottom of that hierarchy about its fields, without passing references to those field(s) through the entire hierarchy.





Greg Brannon
Bartender

Joined: Oct 24, 2010
Posts: 561
An alternative to the biologic model you describe is to use a single source for creating all objects so that it has perfect awareness of what each new object needs and what already exists and can manage the two. Or maybe two management classes, one for user interface and another for data. This last idea roughly describes the Model-View-Controller, or MVC, model, which is not perfect for Java programming, but a good starting place for managing more complex designs. The next step from MVC is the Modified Delegate model.


Always learning Java, currently using Eclipse on Fedora.
Linux user#: 501795
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Edited for clarity:
If I create a single source for creating all objects, how would objects get a reference to that source?

So I make a class like



In this configuration, to create a new object you need to pass to the creator only those elements that the creating object understands as being relavent to the new object and the Creator adds all the other necessary (GUI) elements. The creator must also pass to each new object a reference to itself (using this) so that the new object can spawn the next objects in the chain . So instead of each class in my chain (B,C,D, and E in my first post) being passed a reference to A (the GUI in that example), I am now passing them a reference to the Creator object. That doesn't completely solve my problem.

It does improve the problem in the sense that B,C, and D will at least have SOME use for the passed reference to the master Creator beyond just passing it on to their own objects in the (blind) hope that they might be useful. Further, if the number of objects in A that had to be passed all the way down to E was large, it would save B, C and D from having any references to any of those objects (asside from the ones they also need themselves). This might facilitate garbage collection.


It is somewhat off topic, but that master creator object could have other uses. For instance the type of the returned object could vary. So if ClassB had been sub-classed, then the return value of getB(some parameters) could be any of those sub-classes (including ClassB itself) based on the some parameters. and getB() could be polymorphically enhanced...Interesting, but off topic.



Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39095
    
  23
I would have thought those factory methods should be static. There is a chapter in Joshua Bloch's Effective Java™ about factory methods, which is worth reading.
Greg Brannon
Bartender

Joined: Oct 24, 2010
Posts: 561
Derik said:
In this configuration, to create a new object you need to pass to the creator only those elements that the creating object understands as being relavent to the new object and the Creator adds all the other necessary (GUI) elements. The creator must also pass to each new object a reference to itself (using this) so that the new object can spawn the next objects in the chain . So instead of each class in my chain (B,C,D, and E in my first post) being passed a reference to A (the GUI in that example), I am now passing them a reference to the Creator object. That doesn't completely solve my problem.

Your paradigm as described above begins with a "Creator" (or Controller) model but then reverts to a biologic model where classes created by the Creator then create their own children. An option - not the only option - is for the Creator to be the source of all objects. It's easy for me to visualize this for a GUI program, because I've done it. I can understand that it's harder for you to visualize.

The MVC model begins thusly:

The main() method creates instances of the Model and View. The main() method then creates an instance of the Controller, passing the model and view instances:



Then the controller takes over, interacting with the user through the initial GUI, the view, negotiating the exchange of data with the model as needed. If an action by the user on the view requires a new class, whether another GUI interface or some other object, the controller reacts appropriately and creates the object as needed.

What I've described (not too badly, I hope) is a strict MVC program. The Modified Delegate I mentioned previously allows or defines variations that make sense in a Java program. Either approach provides a way to organize your code so that you don't get to the end of a long chain of objects - especially GUI elements - wondering where you came from, how to get data from multiple levels ago, or how to gracefully return to where you came from once you figure out where that is.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Campbell Ritchie wrote:I would have thought those factory methods should be static.


That is an excellent point. I had not thought of that. If they are static, there is no need for each subclass to be passed a reference to Creator.

Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39095
    
  23
. . . and have a look at Greg Brannon's post and the Joshua Bloch reference I gave you yesterday.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Greg,

Sorry for the delayed repsonse. I have been going over what you said in my head for more than 24 hours. Trying to visualize this new system. I am trying to formulate a coherent concise question (that won't make me sound like the noob that I am). To that end, let me make it more concrete by drawing from one of my recent projects.

I have a program that creates a the View (Class A - the GUI), and passes that to ClassB (Controller) in ClassB's constructor. Then B, which runs in its own thread, takes over all program operations. It continues to take messages from ClassA (the View) via an ArrayBlockingQueue, but the controller runs the show. ClassC and ClassD are what I thinkyou would call the model. And Class E are some background tasks that may need a progress bar.

Now the thing is, ClassC and ClassD are not single classes that can be passed to the Controller (B) because these are both hierarchies of classes.

The way my application works now (in the biological model as you described it) is that ClassB (controller) instantiates one (or more) members of the ClassC hierarchy. Each ClassC objects then examines local and remote resources(of a particular type), and generates one (or more) members of the ClassD hierarchy and tests them until it achieves a valid 'set'. Sometimes a ClassC object will be unable to generate a 'set' and it goes idle. Depending on input from the GUI (View) (and previous history) the controller will pass instructions to the non-idle ClassC objects which will use whatever instances of D they have to carry out the tasks. ClassD objects will, in turn, spawn members of the ClassE hierarchy if (and only if) they have some task that can't be done quickly.

So my question to you is this, 'what part of all that is my model'. There doesn't seem to be any way for the Controller (B) to generate the D objects that each C would need unless it had in it all the functionality of ever member of the class C hierarchy. And it couldn't control the spawning of E objects unless it also had the functionality of every member of the ClassD hierarchy. In non OO languages, there would be no classes. Only piles of functions that were interconnected in complex ways and I could envision a controller that did all that. Most of my experience is with exactly that kind of code.

If a background task (ClassE) wants to announce to the user that it has started (or ended successfully) it needs a reference back to the GUI (or at least back to the controller. The goal is to get that reference to E objects without first passing it through C and D. I could set up (static) factory functions in the controller (ClassB) as described previously. But I have a feeling that this is NOT what you had in mind when you suggested that I wasn't visualizing the MVC model correctly. I think that somehow, my notion of a "model" is not fully developed and that I should have written the functionality of C and D differently.

Greg, I know that was a lot to read. If you have made this far, then you have my thanks. If you can offer any insights at all, I would be most gratified to learn.



Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

I can't speak for Greg, but I have great difficulty relating to designs whose classes have names like "A" and "B". If you told me you had a Customer with several Stores, or a Dragon with several Weapons, or a Journey with several Stops, it wouldn't be so difficult. But when you say you have a B with several C's, that just makes my eyes glaze over.
Greg Brannon
Bartender

Joined: Oct 24, 2010
Posts: 561
I'm sorry, I'm not following you. It might be the As, Bs, Cs, and . . . that don't really mean anything to me, or it might be that I don't understand what in the heck they're all doing and how what they're doing is related to each other.

So, to keep the conversation general, the Model is the keeper of the data. The Model collects stored data, creates and initializes fields/variables as needed, and generally organizes the data into data structures for use by the program. Methods which operate on the data are included in the Model, isolating or encapsulating the data from the rest of the program to the greatest degree possible. You can Google and find an editorial or blog that says "data encapsulation is the most important concept to grasp when programming with objects." That might be overstating, but it's certainly important. While there can be several views and more than one controller (especially in the Modified Delegate model), it would be more difficult to program strict data encapsulation with multiple Models.

I don't know what class performs the Model function in your program. You may have your data sprinkled throughout so that each of those A, B, C, and XYZ classes perform as Models. When you have a large program already constructed or designed that way - one that works! - the thought of restructuring it is scary and may be impossible to justify.

I went back to review why you started this conversation, and at the start of the thread you seemed to be interested in learning a new way to program that resulted in a different product. I don't know your motivation, but I would assume you might, in part, be motivated to write more maintainable, understandable, and reusable code that can be more easily modified as requirements change. So I don't know whether you're trying to change an existing design into something better or you're hoping to do better with your next design.

I suggest you try to do better next time. If you set design goals as you embark on a new design, perhaps the challenges you see above - either because you're imagining a change to an existing design or you're starting a new design with the old one still fresh in your memory - won't be as formidable as they seem.

Good luck. Keep thinking and coding.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Hi Paul,

Re: Stones and Dragons,

I see what you mean, I could have been more creative. If you want to do a global replace you can say

A is a MainGUI (the view)
B is a MainThread (the controller)
C is a ResourceManager (rather all ClassC objects extend AbstractFileManager)
D is a Resource (rather all ClassD objects extend AbstractNetworkConnection or AbstractUSBConnection)
E is a ResourceTask (rather all ClassE objects extend DirectoryWorker which extends SwingWorker)

Maybe it is my math major background but I actually though A through E would be easier to read than the real thing.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Greg Brannon wrote:I'm sorry, I'm not following you. It might be the As, Bs, Cs, and . . . that don't really mean anything to me, or it might be that I don't understand what in the heck they're all doing and how what they're doing is related to each other.

Methods which operate on the data are included in the Model, isolating or encapsulating the data from the rest of the program to the greatest degree possible.

Okay, now we are getting somewhere. What if a method deep in the Model needs a reference to the View? It is a MODEL method. The model doesn't really know about GUI's in general and doesn't care to know. I am only adding GUI feedback as a courtesy to the user so they know something is going on. I think the problem is that the tasks that require GUI feedback are all deep in the model. They cant be generated easily by the controller class without relying on the many layered (nested) methods of the model. How do I get a reference to the View(GUI) deep into the nested layers of the model?

Maybe it is my background in non-OO approaches but I want to think of the GUI as a global resource avaliable to all callers, but I don't know how to publish its existence.


Greg Brannon wrote:I don't know your motivation, but I would assume you might, in part, be motivated to write more maintainable, understandable, and reusable code that can be more easily modified as requirements change.


That was it exactly. I already have a version that works. I had to make it less speghetti code so I could add new functionality. While I was at it, I came across this problem (again). No matter how I do it, I end up passing around this reference to the GUI. If you are going to pass a reference to a variable to every class in your program, you might as well make it global. But Java has no way to do that (presumably for a good reason).



Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Okay I think I have it!

What is wrong with this.




Now, when anything created by the Controller needs a reference to the view, then it can get one by calling the static method getView. The method could return null if the class variable called list hasn't been initialized by at least one instantiation of the master controller, but the only way that can happen is if main() calls the method or the constructors of View or Model call it. It could also be a problem if there were two different constructors pointing to two different Views.

Asside from those caveats, is this bad programming technique?
Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3647
    
  16

I'm sorry, I only just popped in and haven't read the majority of the discussion here yet, so what I say may already have been said or implied by others. If this is the case, I apologize.

You're putting too much focus on the controller part. Usually, the C in MVC is very subtle, and often not nearly as distinctive as the model and the view.

Here's how I normally apply this pattern:
Now, in case your view is a GUI that has buttons and stuff, the 'controller' is made up by all the action listeners that are part of it, and which in turn call methods on model. Your controller may also be a standalone class that accepts user input through the console, and then translates it into method calls to the model.

In general I don't think the View and the Controller need to know about each other's existence. They both need to know about the Model. Controller manipulates Model, and View displays it.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Stephan,


I like your pattern of having the view register itself as an observer of model. But...

In your code, who calls "View.setModel"? It would seem that this would need to be either the creator of Model, or the Model itself. In the case of the latter, how does Model get the reference to the view? If called from the creator of model then when where does the creator of model get the reference to View? From its own creator and its creator's creator before that? And so on up the line until you get to either the top level Model.

The purpose of this thread is to figure out a sane way to get that reference to View into the deep layers of the Model without passing the reference through all the layers on top of that.

I have tested the solution in my post just before yours to work (functionally). But I am not comfortable with it. It seems like round about way to make a global (read only) variable. And maybe that is okay. As long as controller doesn't change it, all will be well.



Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57


Greg Brannon wrote:(especially in the Modified Delegate model)


Greg, to further my education I have looked around a little bit and I can't find a good reference for the Modified Delegate model. Could you please refer me to some reading material?

Thanks in advance,

Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3647
    
  16

Whatever created the View will also create the Model, and then pass the Model to the View.

Let's look at it from the perspective of a simple GUI application, like a game of chess.. Let's call the model class ChessGame, and let's call the view class ChessPanel. The main class we'll call ChessForm. ChessForm already contains an instance of ChessPanel it created itself when it got constructed. Suppose ChessForm has a menu button that starts a new game. When you click the button, its action listener will create a new instance of Chess, and pass the reference to the ChessPanel's setChess() method.

The controller in this case will be the various event listeners in ChessPanel that react to user input, and manipulate the Chess instance accordingly.

Greg Brannon
Bartender

Joined: Oct 24, 2010
Posts: 561
I often start with this article, because it's "official," but I sometimes find it too technical and hard to understand. Even so, it presents the idea and has a diagram that helps visualize it. There are others that do a good job of explaining MVC and then how it can be modified or extended to a Delegate or Modified Delegate model, but the context of some of them is not "pure" Java - they have other agendas - but that doesn't make them bad.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Greg,

thanks I have added that to my reading list.

Stephan,

you have the controller (Form) register a new ChessGame object (model) with the ChessPanel object (view) via the call to setGame(game). The View then registers itself as an observer of the Model via the addObserver(this) call. When the observable model makes a change it calls on the observer(view) to handle it. In this case the model would be calling a ChessPanel.update() method. In theory there may be multiple observers registered for a single model and any given ChessPanel may (in theory) could be observing more than one model, but I wont' cover any of that. It is all very good.

So far, so good. The crux of my question (the very first post), in the context of this example, would involve the details of the implementation of ChessGame. In particular how do the objects that are created inside the model to carry out the complex tasks told about the list of observers? You did not provide that code here (whcih is good) so let make up some pseudo code within the confines of your example to demsonstrate my problem. (this won't compile.... pseudo code).



And I can now demonstrate my problem. The method Thinker2.think needs to update the progress bar as it thinks. But wait! how does it do that? It doesn't know about observersList which is defined way up in ChessGame class. Of course, ChessGame could have passed a reference to observerList on to SmartPlayer in its construction. And SmartPlayer could have passed that reference on to all its Thinker classes. So all the members of ComputerPlayer hierarchy are taking references to an ObserversList, and then just blindly passing it during construction of their Thinker's. This is not destructive, but it is not elegant. The members of the ComputerPlayers hierarchy don't use that reference to observersList themselves. They don't need it _except_ so that they can pass it along to the Thinkers. And most of the Thinker's won't need it either (e.g. Thinker1). Thinker2 updates the progress bar itself, but it might makes sense, in some other circumstance, to have the ThinkerTask worker do that. So some theoretical Thinker3 class needs to take a reference to the observersList, not to use itself, but only so that it can pass it on to its own background ThinkerTask3.

Now, suppose it is not just the progress bar that needs updating? suppose there is a text field in a different frame that I need update? Now I have to two references through that chain. And suppose instead of just 2 or 3 layers, as I have shown here, you have 6 layers in your model and only the bottom one needs access the view?

Of course, I could re-write ChessGame so that it didn't have so many layers (maybe). But that isn't always possible. Sometimes to get good encapsulation, and good re-use of code you need multiple layers. And it is not just OO languages. I had the exact same problem in a program I wrote a few years back in C. I was passing a char* all over the place so I could avoid adding my first gloabal variable to an otherwise global variable-less program. When I was done I wondered if it the code would have been better overall if I had just put in the global.



Edit: I forgot to point out that ChessGame is already passing along references to whitePieces, and blackPieces to it's ComputerPlayer object. In the case of SmartPlayer (and probably other kinds of players) these are not used by the players themselves, but are just passed along to Thinker members in their construction. I didn't show it, explicitly but it seems likely it would have been necessary to pass this along during construction/initialization of the thinker task.


Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3647
    
  16

You're reversing responsibilities here. Thinkers are part of the model. They do not have the responsibility of updating the view.

Instead, your ChessGame class should provide getters to its Thinkers, so that the GUI may determine for itself how far the Thinkers have progressed.
Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3647
    
  16

To use your letter system as an example:

Let's say A is our model's main class. A has a B and B has a C. How do we display changes in C in our ViewA?

ViewA has a ViewB. ViewB has a ViewC. (Maybe ViewA is a form, and ViewB is a panel and ViewC is a progress bar). ViewA doesn't really know about ViewC. It just knows that it's responsible for displaying A, and it does so by querying A for a reference to B, the displaying of which it then delegates to ViewB. ViewB in turn gets a reference to C from B, and passes it to its own ViewC, which is responsible for displaying updates to C.

You can make this daisy chain as long as you want, without having to pass arguments to enormous parameter lists.



Example: in step 8) main.va passes a reference to main.a.b to main.va.vb.setB().
If main.va has registered itself as a listener with main.a, it only has to wait for notifications from main.a, and then it can pass the notifications down to main.va.vb which in turn updates its display based on data in main.a.b, and after that it bubbles the notification down to main.va.vb.vc.

This notification passing mechanism is already completely handled for you in Swing. All you need to do is make ViewA implement some sort of listener interface (like Observer) and then call repaint() in its update() method. This is assuming that ViewA, ViewB and ViewC are all JComponents.

A then needs to be able to register listeners, and when B changes, it tells A to notify its listeners. The same goes for C, C notifies B when it changes, which in turn passes the message on to A.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Stephan van Hulst wrote:
Instead, your ChessGame class should provide getters to its Thinkers, so that the GUI may determine for itself how far the Thinkers have progressed.


Since ChessGame doesn't create those Thinkers directly, how could it provide such a list to the GUI? Two ideas jump to mind.

1. There could be a Class variable which was a list of thinkers and a class function (static function) that allowed new Thinker objects to register themselves on that list during their construction. ChessGame.getThinkerList() could return that list. Option 1 is essentially the same thing as the post I made on Thursday, September 08, 2011 5:07:26 PM, except that instead of having new thinkers contact the controller and get a reference to the GUI so they could register themselves as an observable to the GUI directly, they instead register their existence with the Controller and let the GUI query the Controller for their existence when the GUI needs to repaint. I could see advantages to either method depending on the circumstances.

2. A second solution is a follows, ChessGame.getThinkerList() could call all its ComputerPlayer objects and request the list from them. These in turn could pass the request on to each Thinker object they had created, which could, if appropriate, return a list of their ThinkerTask objects. No need for static functions and class lists. Again, no need for chaining pointers through constructors. There are a bunch of pass through calls, but these would each be fairly simple and their function could be easily grasped and/or documented.


EDIT: You have proposed something similar to Option 2 in your later post which I will comment on in my next post. I now realize that what you describe below is fundamentally different than item 2 because the system below does require chaining references on the model side(only).
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Stephan van Hulst wrote:
This notification passing mechanism is already completely handled for you in Swing. All you need to do is make ViewA implement some sort of listener interface (like Observer) and then call repaint() in its update() method. This is assuming that ViewA, ViewB and ViewC are all JComponents.

A then needs to be able to register listeners, and when B changes, it tells A to notify its listeners. The same goes for C, C notifies B when it changes, which in turn passes the message on to A.


First, it is unfortunate that your code snipit or graphic link was not displaying. Fortunately your description afterwards was so good that I could fill in the parts I didn't get to see. You made a good description of how ViewA delegated some its drawing responsibilities on to the ViewB objects which it had created and how, in turn the ViewB's would pass some of that responsiblity on to View C's (a pattern that I am familiar with). I especially liked how you took that pattern and mand analogy to how the C objects would alert their containing B objects of their changed status so that B could pass that information up to A, allowing A to 'deal with it'.

I like the analogy, but it just masks the problem I posed originally. Why? Because now when A creates B, it must pass a reference to itself on to B during B's construction. It must do this so that B can get back to A when B's state changes (or when it detects a change in one of its own C objects). B, in turn, passes a reference to itself to all the C objects that B creates. Passing this pointers _down_ the chain of created objects so that the objects at the bottom can send messages back up to top, is exactly the same as having passed the reference to the GUI down the chain so that objects at the bottom could send messages to the GUI. This is what I was trying to avoid in the first place. If Object B never changes state in such a way that it needs a redraw from the screen, it seems a shame to have to pass it a pointer to its creator just so that it can use that reference on behalf of the C objects that may need it later.

Note, this is where the analogy breaks down. When ViewA calls on ViewB to do stuff, it does not need to pass a pointer to itself to that B object. ViewA made ViewB so of course it has a reference but the reference chaining stops there. There is no passing of pointers (references) down from A to C, nor any need for ViewC objects to pass notification of changes of state back _up_ to their creators or their creator's creator as there is in the case of the model.


That seems a little long winded, but I think you get the gist of it.




Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3647
    
  16

Derik Davenport wrote:Passing this pointers _down_ the chain of created objects so that the objects at the bottom can send messages back up to top, is exactly the same as having passed the reference to the GUI down the chain so that objects at the bottom could send messages to the GUI.

Not really, because that would make the model "care too much" about the view. It's all about putting the responsibilities with the right classes, and having to send a pointer more or less is less important than that.

This is what I was trying to avoid in the first place. If Object B never changes state in such a way that it needs a redraw from the screen, it seems a shame to have to pass it a pointer to its creator just so that it can use that reference on behalf of the C objects that may need it later.

But if C objects -- which the B object is composed of -- change, that automatically implies that B has changed. That's the entire point.

Note, this is where the analogy breaks down. When ViewA calls on ViewB to do stuff, it does not need to pass a pointer to itself to that B object. ViewA made ViewB so of course it has a reference but the reference chaining stops there. There is no passing of pointers (references) down from A to C, nor any need for ViewC objects to pass notification of changes of state back _up_ to their creators or their creator's creator as there is in the case of the model.

This is logical, because notifications travel from left to right (if you can see my image). So there need to be pointers from left to right. The right half (from ViewA to ViewC) "naturally" have these pointers. The left half (from C to A) these pointers have to be established first.

The thing is, you will *always* need some sort of pointer from some place to some place, if the latter is be notified of changes in the first.
Personally I like creating models in which only one central class is observable, and its 'underlings' report to it when they have changed.

An alternative route you can take is make each class you want to observe observable. This way C objects don't need a reference to B, they just maintain a list of observers themselves.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Stephan van Hulst wrote:
Not really, because that would make the model "care too much" about the view. It's all about putting the responsibilities with the right classes, and having to send a pointer more or less is less important than that.

Okay. That's a valid distinction.


But if C objects -- which the B object is composed of -- change, that automatically implies that B has changed. That's the entire point.


If B is a connection to a Server, and C is file on that server, then I don't see B has having changed states because one of its files has changed state. But maybe I see that wrong. If I am to view B as a connection to every file on a remote server instead of a connection that contains files, then I should really not bother having layers to distiquish files from the connection and instead have one big super class that covers both files and connectivity. But then that prevents me from re-using the file behavior when I connect to a different kind of server. Nevertheless, when viewed as "passing information from left to right as in your diagram - (which now displays just fine by the way) it makes some sense. I can see that when B creates C (to its left) it must assume the responsibility of passing the existence of that item on to the View so that the View can do its job of displaying state information. Either that or it must agree to pass state information (or at least changes in state) for its created objects up the chain until you get back to the controller.


An alternative route you can take is make each class you want to observe observable. This way C objects don't need a reference to B, they just maintain a list of observers themselves.

This is the way I have done it in the past. But I thought maybe I was doing something terribly wrong because to get the list of Observers to C, that is to say for C to find out about the one important observer (what you call Main in the diagram), I had to pass that reference down the pipe through A and B.



Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3647
    
  16

Derik Davenport wrote:If B is a connection to a Server, and C is file on that server, then I don't see B has having changed states because one of its files has changed state.

Your example is invalid. A class that models a server connection would never hold references to instances of a class that models files. It retrieves files, but they are not part of the class.

This is the way I have done it in the past. But I thought maybe I was doing something terribly wrong because to get the list of Observers to C, that is to say for C to find out about the one important observer (what you call Main in the diagram), I had to pass that reference down the pipe through A and B.

No, you can do it differently. For example, make C extend the Observable class, and when ViewC gets a reference to an instance of C in its setC() method (through a chained method call from ViewB.setB()), ViewC itself will register itself as an Observer of C. There's no need to pass a list of Observers down to C. Every Observer (whether it's a GuiViewC or a ConsoleViewC or something else) can register itself with C after it's gotten a reference to it.
Derik Davenport
Ranch Hand

Joined: May 30, 2011
Posts: 57
Your example is invalid. A class that models a server connection would never hold references to instances of a class that models files. It retrieves files, but they are not part of the class.


Stephan, I had a long think about that. It points out a rather muddled point in my thinking about my project. If my class represents only a connection, then you are right, it should not be holding the references to the files. On the other hand, if that class represents a server then it can hold the file references, but then those files are "a part of" the server and changes in the state of the files represents a change in state of the server. That is, a serve, must take responsibility for passing ChangeOfState events up the chain. If I get a chance I am going to rewrite the enumerateFiles() methods in my Connection classes to return the List<RemoteFile> to the caller rather than just keeping that list inside the Connection class.

No, you can do it differently. For example, make C extend the Observable class...


Yes, of course. I didn't mean to discount the value of using "set" functions, as you named them, to get the references to new C's back to ViewC so that ViewC can register as the Observable C. As I mentioned earlier, your method of "set" functions has advantages, over passing references to ViewC (or other Observers) down the chain from A to C. It is still just a means of getting a reference to something on the right side of the diagram (the Observers) to the objects on the far left side of the diagram (the Observed) without using a global, and understanding the alternative methods for doing this kind of thing was the goal of my original post.

It has been a very educational discussion for me.

Thanks,
DD

 
GeeCON Prague 2014
 
subject: designing for multiple layers