views:

180

answers:

5

I'm currently experimenting with the Google's guice inversion of control container. I previously had singletons for just about any service (database, active directory) my application used. Now I refactored the code: all the dependencies are given as parameters to constructors. So far, so good. Now the hardest part is with the graphical user interface. I face this problem: I have a table (JTable) of products wrapped in an ProductFrame. I give the dependencies as parameters (EditProductDialog).

@Inject
public ProductFrame(EditProductDialog editProductDialog) {
  // ...
}

// ...

@Inject
public EditProductDialog(DBProductController productController, Product product) {
  // ...
}

The problem is that guice can't know what Product I have selected in the table, so it can't know what to inject in the EditProductDialog.

Dependency Injection is pretty viral (if I modify one class to use dependency injection I also need to modify all the other classes it interacts with) so my question is should I directly instantiate EditProductDialog? But then I would have to pass manually the DBProductController to the EditProductDialog and I will also need to pass it to the ProductFrame and all this boils down to not using dependency injection at all.

Or is my design flawed and because of that I can't really adapt the project to dependecy injection?

Give me some examples of how you used dependency injection with the graphical user interface. All the examples found on the Internet are really simple examples where you use some services (mostly databases) with dependency injection.

A: 

I believe Guice usage in Desktop GUI development works best for Service configuration.

With your approach you would need to configure interaction scopes properly to be able to inject user domain objects that are selected in the GUI properly into services.

Instead you could make the selection data accessible from a service which is injected as a singleton service into other services which require selection data.

The SelectionService could be something like this

public interface SelectionService {

    Product getSelectedProduct();

    // ...

}

In Web GUI development you have for example Session and Request scope. I believe that scoping is more difficult in Desktop GUI programming, so I'd go for DI for singleton services and wiring of static GUI components and manual instantiation for everything else.

And if you need to make Selection data available as a Service than the code snippet could be of help.

Timo Westkämper
A: 

Depends on what we mean by "GUI".

I wouldn't use DI for JSPs, but I would in the controllers that interact with them. I consider controllers to be part of UI. I inject the validators, mappers, and services they need to fulfill requests and craft responses.

If you agree, then DI is appropriate for the view layer.

duffymo
+1  A: 

A composite GUI can certainly make use of DI. However, you will have to be dogmatic about maintaining a composite-orientation. Any direct coupling between interface elements will create a lot of headaches.

hemp
+1  A: 

The problem is that guice can't know what Product I have selected in the table, so it can't know what to inject in the EditProductDialog.

Use dependency injection for dependencies that can be resolved by Guice (when the application is started). Use method arguments for setting any state of your services that is determined by application logic and therefore only known later, at run-time.

In this specific case, the code which decides which product to show (presumably the ProductFrame which knows the selection in the table) would invoke a SetProduct method on the dialog before showing it.

Wim Coenen
+1  A: 

From what I see in your sample code, I am not sure passing Product to EditProductDialog is the best design, this means that you cannot reuse the same dialog for 2 different products.

In general, I would rather add a setProduct(Product) to EditProductDialog in order to:

  • enable reuse of the same dialog
  • allow constructor injection of the dialog itself

Besides, you can also, if you want to keep the current constructor arguments, take a look at Guice Assisted Injection, which would allow you to have all dependencies injected into the constructor, while still providing the product explicitly.

Finally, you may want to take a look at Guts-GUI, an open source framework for creating Swing GUIs with Guice (still under work, but ready to use as of today). It has a sample application that contains examples of reusable dialogs.

jfpoilpret
I was thinking of the same solution, but I wasn't sure that it's the best approach because with dependency injection you "need to declare your dependencies" (in the constructor in the case of guice). But this seems the best solution right now.Thanks for the links. They are definitely helpful!!!
Igor Popov
Another approach I was thinking is to use guice only for services (database etc) and for the gui classes just to pass the injector as a parameter. I'm not sure of this approach either.
Igor Popov
Don't do that! Directly using Guice Injector in application code must be considered a design smell, this is contrary to "Inversion of Control" and looks like the "factory pattern" instead. Only frameworks or libraries might have this need and only in rare opportunities.
jfpoilpret
"Factory Pattern"? I knew if I use guice like that then it degrades to the "Service Locator Pattern" (a central object that knows about any service available in an application).
Igor Popov
Please also note that Guice doesn't impose constructor injection, it can also perform method injection (not just setters, but any method even with several args for dependencies) and even field injection. However, construction injection is normally a good practice because it allows using final fields and thus prevents mutability of fields that should not change.
jfpoilpret
Yeah sorry for the mistake, you are right, this is service locator pattern in this case. But that doesn't change the fact it is bad design;-)
jfpoilpret