8

Suppose I have a Widget class that is part of a framework used independently by many applications. I create Widget instances in many situations and their lifetimes vary. In addition to Widget's instance specified methods, I would like to be able to perform the follow class wide operations:

  • Find a single Widget instance based on a unique id
  • Iterate over the list of all Widgets
  • Remove a widget from the set of all widgets

In order support these operations, I have been considering two approaches:

  1. Container class - Create some container or manager class, WidgetContainer, which holds a list of all Widget instances, support iteration and provides methods for Widget addition, removal and lookup. For example in C#:

    public class WidgetContainer : IEnumerable<Widget>  
    {  
      public void AddWidget(Widget);  
      public Widget GetWidget(WidgetId id);  
      public void RemoveWidget(WidgetId id);  
    }  
    
  2. Static class methods - Add static class methods to Widget. For example:

    public class Widget
    {
      public Widget(WidgetId id);
    
      public static Widget GetWidget(WidgetId id);
      public static void RemoveWidget(WidgetId id);
      public static IEnumerable<Widget> AllWidgets();  
    }
    

Using a container class has the added problem of how to access the container class. Make it a singleton?..yuck! Create some World object that provides access to all such container classes?

I have seen many frameworks that use the container class approach, so what is the general consensus?

1
  • it not clear why existing generic containers don't meet your needs
    – jk.
    Commented Nov 2, 2012 at 15:12

3 Answers 3

9

The modern consensus is that you should not do this at all.

Having a 'all instances of this class' design has proven to be troublesome in many aspects, the foremost being with regards to concurrency. Do you want all widgets, or all widgets owned by your thread? Do you really want to make that all widget list threadsafe? Remember that unit tests are almost always done in parallel, so "my app is single threaded" might not be good enough.

The other problem you run into is in your design. With the 'one and only' list of anything, be it global, static or singleton you'll quickly run into issues when you need more than one. You'll run into issues with temporary widgets or offscreen widgets if they're automatically added to the list. You'll run into errors where you forgot to add them to the list if they're not automatically handled.

Once you don't have the 'all instances of a class' requirement, then you end up with a plain old collection. Whatever consuming code is working with the widgets (even if that's some framework that is in turn consumed) can orchestrate how the collection is used and how/when the widgets get put in there. The widgets themselves should not care.

3
  • Possibly a pool pattern applies, but need more info and as otherwise noted, exercise caution.
    – JustinC
    Commented Nov 2, 2012 at 16:59
  • @Telastyn: Good point! Having a Widget class with static GetAll method or singleton collection will limit the framework to having one global list of Widgets and that is a serious problem.
    – Ben
    Commented Nov 2, 2012 at 17:43
  • @pdr: You are right, I guess my question boils down to: If I have several of such collections of class objects (i.e. WidgetCollection, SomethingElseCollection, etc) what is the best way, from an framework API perspect to provide access to these collections. I am currently using a World object, where the caller creates a World object which contains instances of each collection. The caller accesses the collections through the World object.
    – Ben
    Commented Nov 2, 2012 at 17:46
1

This seems to be a good candidate for using an IoC (Inversion of Control) container. Instead of having to create the container yourself, you just rely on a generic container part of an IoC library which you can call upon.

For example you would define an interface:

public interface IWidgetHandler
{
   void AddWidget(IWidget widget);  
   IWidget GetWidget(int widgetId);  
   void RemoveWidget(int widgetId);
   IEnumerable<Widget> GetAllWidgets();
}

Then you define a class that implements that interface.

public class WidgetHandler : IWidgetHandler
{
    public void AddWidget(IWidget widget)
    {
        throw new NotImplementedException();
    }

    public IWidget GetWidget(int widgetId)
    {
        throw new NotImplementedException();
    }

    public void RemoveWidget(int widgetId)
    {
        throw new NotImplementedException();
    }


    public IEnumerable<Widget> GetAllWidgets()
    {
        throw new NotImplementedException();
    }
}

You would register how you should find instances of WidgetHandlers with an IoC container.

Generally, an IoC container has some sort of registration method so you can call

MyIoCContainer.Instance.Register<IWidgetHandler, WidgetHandler>();

Now whenever you need a widget handler you just tell IoC to give you an instance of one.

IWidgetHandler widgetHandler = MyIoCContainer.Instance.Resolve<IWidgetHandler>();

The IoC container can also control the lifetime of your objects.

Have a look at the ninject documentation if you want further details on getting up to speed with IoC. There are also a few more options out there (unity, autofac, Castle just to name a few). In fact there is a CommonServiceLocator library that provides a common interface for all, with the lowest common denominator of useful functionality (should you want to swap between them)

It allows your code to be more testable when compared to static methods classes since these can be mocked when a piece of code depends on an IWidgetHandler. Instead of serving up a real widget handler, IoC (or the test framework) can serve up an instance of a FakeWidgetHandler which can be used to test the code that depends on this module by serving up various fake responses to the code and asserting that method parameters are passed correctly down to the IWidgetHandler dependency.

Good luck!

6
  • 1
    Agree, but that's not really answering the question. A single-instance container inside an IoC container is almost as bad as a singleton. Not to mention the issues with having an always-accessible singleton of your IoC container (ie. Service Locator).
    – pdr
    Commented Nov 2, 2012 at 15:37
  • The default behaviour for register in an IoC is not for registering single instance, but what is known as a transient lifecycle. It will serve up a new instance of a widget handler whenever resolve is called. The posted sample in the question seems very 'crudy' as if querying some sort of data store. Either Active record or Repository can apply, in which case I would point to here Commented Nov 2, 2012 at 15:47
  • What are you calling resolve on? That service locator is what pdr is referring to...
    – Telastyn
    Commented Nov 2, 2012 at 15:54
  • @Anastasiosyal: I get that. The point is that Ben's question, once you cut through the words, is "How do I avoid having a single instance of a container but have the widgets accessible from all over my code?" Your answer, while great advice, doesn't answer that question. If the WidgetContainer is Transient, it isn't accessible from everywhere; if it's Single-Instance, the problem remains.
    – pdr
    Commented Nov 2, 2012 at 15:59
  • @pdr ok, I see where you're getting at.I guess it all boils down to, does the widgetContainer have any state. If it does not have any state, it can be registered in an IoC container which will serve up transient instances of it that enable the consumption of the exposed methods. I see the widget container as a pretty much stateless class with a dependency on some sort of data store. As such it can live in IoC. Without additional info it's a bit hard to say. But I wouldn't rule out IoC based on the assumption that 'its got to be a single instance' as there doesn't seem to be such a requirement Commented Nov 2, 2012 at 17:02
0

There is absolutely no difference between having a Singleton object and using static methods on the Widget class. Widget.GetWidget and WidgetContainer.Instance.GetWidget carry exactly the same problems.

Where and in what form are your widgets when the application isn't running? That will help solve your problem.

If they're in a database or on the filesystem then you don't need a single-instance object to access them, for example. Any number of WidgetContainer objects can get them from the file-system or database, independently. You can implement a caching system if performance is your concern.

7
  • With the singleton you could pass the instance around, not just pull it out of the global scope everywhere.
    – Sign
    Commented Nov 2, 2012 at 16:19
  • @Sign: Well, you could. But what does that gain you?
    – pdr
    Commented Nov 2, 2012 at 16:24
  • it can simplify your testing concerns since you aren't mucking in global state. You can reference it as an interface to break the hard dependency. You can use a dependency injection framework to do the singleton stuff for you.
    – Sign
    Commented Nov 2, 2012 at 16:28
  • 2
    Testing isn't his primary concern but it is a concern and when the two solutions are otherwise equivalent it makes one clearly better. And since this is a framework the other applications may be interested in stubbing out his framework for testing purposes.
    – Sign
    Commented Nov 2, 2012 at 16:44
  • 1
    Then there is a difference between the two. Which contradicts your first sentence. But at this point I feel like we are talking past each other.
    – Sign
    Commented Nov 2, 2012 at 17:10

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.