5

I often find myself in situations where objects need to communicate between each other. For example, a button might need to talk to various textboxes. Would it be proper to simply construct each widget with a pointer to the container for all of them? Would it be better to give it a pointer to a resource container map where the object can locate another object by string or something? This area has always been very vague to me. I could easily implement everything I want to do if I just constructed objects with pointers to containers of every other object, but that seems wrong. In the case of a widget, would it actually just be more proper if the widget knew nothing about the outside world and instead its action listeners were constructed with resource access?

Thanks

I understand that it is a bad idea but what are some solutions in these situations eg: good design patterns for gui oriented software?

If a button's click needs to write a file, how can that be done in a clean way? Action Listeners? But where do they get created and by what?

1

3 Answers 3

4

It is best if you separate out business logic from state / UI generated code. If you add biz logic directly to the generated Action listeners its an anti-pattern. You will end up with very fragmented logic that gets harder to maintain as you add more buttons.

Build your basic business logic like you would model any software problem. Add GUI on top of this as an activator. In worst case scenarios you could query GUI to figure out the current state of check boxes etc., but ideally you should be maintaining this state in your biz logic layer. Decoupling like this will save you a lot of pain later. Read up about MVC patterns.

Once you go down this path, you will find that you don't need a world pointer, but just a pointer into the controller object which can tell you whatever you need.

0

Lots of different questions here, you might have been better off asking this in 2 or 3 separate posts, but let's see what happens...

1) "the world" I guess is a relative term. I wouldn't give a pointer value to "the world", but based on your example, I'd say go ahead because I wouldn't consider a container of a widget to be "the world". On the other hand, if you created a set of objects based on external client request and then instead of unique identifiers, directly used pointers as the identifiers, that would be giving a pointer to internal memory to the world. I'd avoid doing that.

2) I would consider objects (or widgets) containing pointers to other objects (or widgets) to automatically be bad design. You obviously want to keep things as loosely coupled as possible but I can see some situations, where this would be acceptable. Loosely coupled simply means you want each of your objects (or widgets) to only know as much about the others as absolutely necessary (and not make any assumptions about internal implementations)

3) I've done numerous designs where you have a parent container and a set of children. One thing that I always try to do is avoid circular dependencies where object A knows about B and B knows about A. Typically when you do that, you are asking for trouble. Instead I would define a child (our widget class) and next to it define "IWidgetOwner" or "IWidgetKeeper" (ghostbusters reference) interface. Then have the parent implement this interface and pass a pointer to every child. Now you have a very clear hierarchical relationship. Your container knows about widgets that it contains, but widgets know nothing about your specific container. Instead, they can be placed in just about any container that implements your "keeper" interface.

4) Having said all this, if you are doing UI specific work, I would stay away from adding too much business logic inside the GUI controls (widgets) themselves. Instead, I would have a separate layer (class) that would setup subscriptions on the event handlers and define which action should be taken when certain events get fired. This way your widget code stays generic and reusable and all the business logic is wrapped up in a single place so when you do have to go change it, you don't need to look all over your code.

5) A button never "needs" to write a file. Instead, your application needs to write a file in response to a user click. I would always separate code that "does work" from UI as much as I can. Think of the scenario where you want a second button, or global hot key to write the same file? Or what if you want to add automation and you need to write the same file but with no GUI involved at all. When you start a project with a UI, start by defining a very clear line between your GUI and your work. It might seem like too much overhead, but it's just a mental exercise and after you do them a few times, it'll get much more natural so the overhead will almost disappear. But you'll be writing code which is more loosely coupled and better positioned for future expansion.

0

It depends on the scope of your application. If you're talking about a quick and dirty utility with a limited audience, sure, that would be fine. With a bigger audience, you may find features and enhancements will pile on quickly.

Putting a middle manager between user actions and views of data can be a useful endeavor in keeping your code extensible in such circumstances. An established way to do this is to follow a Model/View/Controller pattern. Or, if you're using WPF, look into a MVVM pattern using a ViewModel, data binding, and commands. Going with this early is extra work but will put you ahead of the curve in avoiding major refactors later.

Finally, just to note, when code has references to controls, having a middle man only provides skin deep protection from hackery. In Win32, WinForms, and WPF (and pretty much all UI frameworks) you can walk the control tree. So your controls and their associated code will always have the ability to access everyone else, even with a MVC or MVVM architecture.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.