5

I'm implementing a factory pattern that looks as follows.

public class FeedFactory
{
    #region Singleton Pattern
    //..
    #endregion

    private static Feed[] _factory = new Feed[(int)FeedType.Total];

    public void RegisterFeed(FeedType feedType,Feed feed)
    {
        if (_factory[(int)feedType] == null)
        {
            _factory[(int)feedType] = feed;
        }
        else
        {
            // already registered
        }
    }

    public Feed GetFeed(FeedType feedType)
    {
        return _factory[(int)feedType];
    }
}

Here, Feed is an abstract class from which the different classes inherit. How can I register the different classes? Is it possible to do it from their constructor?

2
  • If you don't do anything in the else clause it is best to remove it, this makes it more readable. Commented Dec 21, 2010 at 10:20
  • See this answer: stackoverflow.com/questions/4387573/… Commented Dec 21, 2010 at 12:27

5 Answers 5

8

This is not a factory pattern. A factory will always have some constructor logic in it, at least one new. That's the idea of a factory: the caller doesn't have to worry about how objects are created. This is a singleton repository.

So first of all, instead of using an array, you should be having a type indexed dictionary.

private static Dictionary<Type, Feed> _singletons = new Dictionary<Type, Feed>();

After that, you don't need a register method. The dictionary should be filled automatically when you retrieve singletons.

Now I suppose your Feed class has a default constructor without arguments. In that case, you can implement a factory method directly from the abstract class Feed. We're going to use some generics here, because it allows you to control inheritance:

public abstract class Feed
{
    public static T GetInstance<T>() where T:Feed, new()
    {
        T instance = new T();
        // TODO: Implement here other initializing behaviour
        return instance;
    }
}

Now back to your singleton repository.

public class FeedSingletonRepository
{
    private static readonly object _padlock = new object();
    private static Dictionary<Type, Feed> _singletons = new Dictionary<Type, Feed>();

    public static T GetFeed<T>() where T:Feed
    {
        lock(_padlock)
        {
             if (!_singletons.ContainsKey(typeof(T))
             {
                 _singletons[typeof(T)] = Feed.GetInstance<T>();
             }
             return (T)_singletons[typeof(T)];
        }
    }
}

Note that I included a threadsafe behaviour which is a good thing to do when you work with singletons.

Now if you want to get the singleton for a given type inheriting from Feed (let's call it SpecializedFeedType), all you have to do is:

var singleton = FeedSingletonRepository.GetFeed<SpecializedFeedType>();

or

SpecializedFeedType singleton = FeedSingletonRepository.GetFeed();

which is the same line with a slightly different syntax.

Edit2: changed some syntax errors.

Sign up to request clarification or add additional context in comments.

7 Comments

When you call typeof(T).GetInstance(),isn't the GetInstance() call supposed to be from the class and not System.Type?
Yes, you're indexing an array of instances by they types. This way you get a relation type => instance, were the instance is the singleton for the given type.
yes, but typeof(T) is a type, not an instance of the feed class. So typeof(T).GetInstance() doesnt make sense
Well yes actually you're right! I'm looking into it right now.
It would make to write T.GetInstance(), the method being static, but it doesn't work. I'm trying to find a way to do it!
|
6

Just as a side note -- as a factory is intended to wrap creation, it's a curious choice that you're creating objects and registering them with the factory. Is this more an object repository than a factory, or is there more to the class than I'm seeing?

If it is an object repository, then you might also find some extra inspiration in other questions, like this one.

1 Comment

Normally a factory would create objects -- a simple implementation would have a factory interface with a Create method, and concrete implementations of the factory class that can create a specific type. There are variations, but the key thing is that it handles creation for you. It could also do what you're doing and cache object instances if you wanted to reuse them, but then you might explicitly want to split factory and cache/repository aspects. It depends what you want to achieve :) If you're exploring at this point I'd get something that meets your goal first.
1

When you call the RegisterFeed method you need to pass a concrete instance of a Feed class. So it is the responsibility of the caller to provide the concrete implementation.

4 Comments

so is the caller one of the types of feed?
The caller can be anything. When it calls the RegisterFeed method it needs to pass a specific implementation of a Feed.
Lets say I have a class FeedTypeA : Feed. If I declare a public static object of FeedTypeA inside FeedTypeA and put the register in the constructor. will that work?
Yes it will work, you could pass this to the RegisterFeed method.
1

Just register the type of the classes you want to create, then use Activator.CreateInstance to create instances of that type.

It should work this way:

private static Type[] _factory = new Type[(int)FeedType.Total];

public void RegisterFeed(FeedType feedType, Type type)
{
  ...
  _factory[(int)feedType] = type;
  ...
}

public Feed GetFeed(FeedType feedType)
{
    return Activator.CreateInstance(_factory[(int)feedType]) as Feed;
}

You can call RegisterFeed like the following:

RegisterFeed(FeedType.SomethingSpecial, typeof(MyDerivedSpecialFeed));

Comments

0
class FeedFactory {


    public IFeedFactory GetFeedFactory(string type) {
       switch(type) {
          case "1": return new Feed1(); break;
          case "2": return new Feed2(); break;
       }

    }

}

Note all Feeds Must implement an IFeedFactory interface and implement the method necessary.

//From the client

FeedFactory ff1 = new FeedFactory();
IFeedFactory obj = ff1.GetFeedFactory("1");
obj.ExecuteMethod();

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.