简体   繁体   中英

Factory Pattern implementation in C#

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?

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.

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 .

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.

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));
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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM