Announcement Announcement Module
Collapse
No announcement yet.
Refactoring from Singleton Anti-Pattern to Dep Injection Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Refactoring from Singleton Anti-Pattern to Dep Injection

    Hi,

    I'm currently refactoring a large Swing application to use the Spring Framework. Unfortunately, the application currently makes heavy use of the Singleton "anti-pattern" to access the business service layer.

    So far, it has been easy to make the IOC container instantiate the service layer objects as beans and to inject them into objects at the "top layer" of the application, that is objects directly involved with the main frame. However, what about objects farther down the food chain? For example (somewhat contrived), what about a model object for a panel that is part of another panel on a dialog that is accessed from a child frame of the main frame? The dependency chain could look like this, for example:

    Code:
    MainFrame
    ->ChildFrame
    ->DialogLaunchedFromChildFrame
    ->BigPanelOnDialog
    ->LittlePanelInsideBigPanel
    ->LittlePanelModel
    ->MyServiceLayerObject
    Currently LittlePanelModel accesses MyServiceLayerObject in singleton fashion. For example:
    Code:
    MyServiceLayerObject.getInstance.doSomeService()
    The question is, how should I refactor this code so that LittlePanelModel does not have to access MyServiceLayerObject in singleton fashion. The way I see it, there are several refactoring options here:
    1) Instantiate ALL of the objects in the IOC container and use dependency injection to inject the service layer dependency into LittlePanelModel. This may seem like the logical choice except when you look at the big picture. This sort of long dependency chain is seen all over the application because there are many, many screens, dialogs and panels in the app. I would have to configure several hundred objects in the application context configuration files. Some of you say "what's wrong with that"? In the long run, I think it might be workable but in the short run, I can only refactor this app in stages. I can't make all of the beans IOC-managed all at once; I have to move towards this goal slowly.
    2) Get the container to Inject the dependency into MainFrame and then pass the dependency along as each object instantiates its helper object in the next link of the dependency chain. I don't particularly like this because objects in the middle of the chain are not directly dependent on the service layer objects; to keep coupling low, I don't want to introduce unnecessary dependencies.
    3) Use "one singleton to rule them all" (this hiliarious Lord of the Rings-ish quote is from the javadocs for Spring's BeanFactoryBootstrap class). In other words, allow singleton access to the bean factory or application context that holds all of the service layer objects. This is still a singleton but at least there's only ONE singleton in the entire app instead of one for each service object.

    Comments or advice?

  • #2
    I think maybe option 3 okay for Swing application. I looking at Spring Rich Client and they have this sort of "one singleton to rule all". It is Application class. If you looking at some Spring Rich Client code, you see lots of classes access this singleton to look up images, icons, rules source, messages, etc. Example:
    - Application.services().getIconSource() in OverlayValidationInterceptorFactory class
    - Application.services() in ApplicationServicesAccessor class, which many class derives from and using it to get images, icons, etc.

    So I think is not big deal if Keith already doing this in Spring Rich Client (if Keith using it, it must be okay for you to use it too :wink: ). Maybe just make sure you have only this one singleton though. Make everything else non-singleton.

    What you other guys say about this one?

    Comment


    • #3
      Originally posted by steve_smith
      I think maybe option 3 okay for Swing application. I looking at Spring Rich Client and they have this sort of "one singleton to rule all". It is Application class.
      Thanks Stefano. My gut was telling me this too. If Spring Rich uses this one-singleton idea, it can't be that bad can it? I mean, as long as I use DI where convenient and also make sure that this is the only singleton, it should be okay, right? This will allow me to convert my existing singletons to beans.

      Does anyone else have a differing opinion?

      Comment


      • #4
        Not that I'm criticizing this idea, but how is this not replacing the "singleton" antipattern with the the ServiceLocater "anti-pattern"?

        A matter of degree or misuse? Or is a ServiceLocator object that is created via DI better then an old style ServiceLocator.

        I guess if you dig deep into any code base (or even cosmology) there is one singleton somewhere.

        Comment


        • #5
          jbetancourt, thanks for your response.

          Originally posted by jbetancourt
          how is this not replacing the "singleton" antipattern with the the ServiceLocater "anti-pattern"?
          IMHO, using one standard singleton provided by either Spring (e.g. BeanFactoryBootstrap, SingletonBeanFactoryLocator, ContextSingletonBeanFactoryLocator) or Spring Rich Client (e.g. Application) has got to be at least a little bit better than using several custom singletons. Using this one singleton instead of several custom singletons has several benefits:
          1) The custom singletons can be converted to "service" beans and we can remove the getInstance() method from each bean. This means that classes that depend on them can now depend on their interfaces instead of their implementations (e.g. you can call myService.someMethod() instead of myServiceImpl.getInstance().someMethod()). This makes it easier to change the implementation or to mock it up for testing.
          2) The properties of these service beans can all be configured in a standard way in the IOC container instead of using ad hoc techniques.
          3) These service beans can be injected with their dependencies (for example, dependencies on a transaction manager) by the IOC container.

          Originally posted by jbetancourt
          Or is a ServiceLocator object that is created via DI better then an old style ServiceLocator.
          Yes, I think so -- see the benefits, above. And note that these "service locators" are beans not singletons; there would be only one singleton left in the app after the singleton services are refactored to service beans.

          Originally posted by jbetancourt
          I guess if you dig deep into any code base (or even cosmology) there is one singleton somewhere.
          This is precisely my point. In Spring Rich Client, that singleton is the Application class. If you use almost any part of Spring Rich Client, you are using this singleton. For example, as Stefano points out, a lot of Spring Rich Client's classes use this singleton to load messages, icons, rules, etc. So that singleton is always there, under the covers. If Spring Rich Client didn't have this singleton, many of Spring Rich Client's classes would need setters for message sources, icon sources, rules sources, etc. Yes, having these extra setters would be flexible, but it could also lead to a lot of extra configuration and also a lot of passing around of dependencies through a long chain of objects (see my first post in this forum topic), where objects in the middle of the chain might not even use the dependency. I'm not sure if this flexibility would be worth the extra hassle.

          In a web app, I guess you don't really need a singleton like Spring Rich Client's Application singleton. But then again, web apps have the servlet context where you can shove your app context, making it pretty much globally accessible. With Swing apps, you don't have the benefit of a servlet context. So, the way I see it, the Application singleton is sort of like the servlet context.

          If our existing app used only Spring Rich Client's Form, View and Dialog related classes, we would probably never see references to the Application singleton in our app's code. Unfortunately, we currently have our own "form", "view" and "dialog" framework in our existing app. At the moment, we don't have time to convert the entire app over to using Spring Rich Client's Form, View and Dialog framework. Therefore, in the short term, I think we must use the Application singleton in our framework to look up messages, icons, rules, etc in a similar fashion to how Spring Rich Client's Form, View and Dialog framework does these lookups. I don't really see the difference between what we are doing and what Spring Rich Client does.

          In theory, I think pure DI would be great but how do I get from here (lots of custom singletons) to there (pure DI) with the least amount of disruption to the existing app? Surely some DI is better than no DI. I think a lot Spring users are in this same situation of having to convert an existing app instead of starting from scratch. All I'm looking for is a little advice on how to do this conversion sanely without having to turn the existing app upside down all at once.

          Comment


          • #6
            cyboc,

            I had to do something very similar (albeit a web app). Everything was looked up via a static factory/registry. My refactoring strategy was to start at the bottom layer by converting the factory to acquire beans from the Spring container. That let the codebase remain stable while I built up the bean configurations. In other words, the first set of beans provided by the factory came from the IoC container, but they themselves still did DL of their collaborators.

            At that point I began modifying those classes to replace the DL with DI. Once that was complete, I continued by moving up layer by layer. Going from the top down, you have to watch that everyone gets the same instance of your singleton since the one used by Spring is only one by virtue of the IoC registry. I may have been wrong, but I thought it would be more problemmatic during a long, complicated refactor.

            This is probably a good discussion for the architecture forum. We need an "Introduce Spring" refactoring with a one button Eclipse plugin.

            Cheers.

            Comment

            Working...
            X