Реализация Factory Pattern в C # - PullRequest
       25

Реализация Factory Pattern в C #

4 голосов
/ 21 декабря 2010

Я реализую фабричный шаблон, который выглядит следующим образом.

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];
    }
}

Здесь Feed - абстрактный класс, от которого наследуются разные классы. Как я могу зарегистрировать разные классы? Возможно ли это сделать из их конструктора?

Ответы [ 5 ]

7 голосов
/ 21 декабря 2010

Это не заводской шаблон.У фабрики всегда будет какая-то логика конструктора, по крайней мере, одна new.Это идея фабрики: вызывающей стороне не нужно беспокоиться о том, как создаются объекты.Это одноэлементное хранилище.

Итак, во-первых, вместо использования массива у вас должен быть индексированный словарь типов.

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

После этого вам не нужензарегистрировать метод.Словарь должен заполняться автоматически, когда вы извлекаете синглетонов.

Теперь я предполагаю, что ваш класс Feed имеет конструктор по умолчанию без аргументов.В этом случае вы можете реализовать фабричный метод непосредственно из абстрактного класса Feed.Здесь мы собираемся использовать некоторые обобщения, поскольку они позволяют вам управлять наследованием:

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;
    }
}

Теперь вернемся к вашему одноэлементному репозиторию.

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)];
        }
    }
}

Обратите внимание, что я включил поточно-безопасное поведениечто хорошо делать при работе с синглетами.

Теперь, если вы хотите получить синглтон для заданного типа, унаследованного от Feed (назовем его SpecializedFeedType), все, что вам нужно сделатьэто:

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

или

SpecializedFeedType singleton = FeedSingletonRepository.GetFeed();

, что является той же строкой с немного другим синтаксисом.

Edit2: изменены некоторые синтаксические ошибки.

6 голосов
/ 21 декабря 2010

Точно так же, как примечание - поскольку фабрика предназначена для упаковки создания, это любопытный выбор - создавать объекты и регистрировать их на фабрике. Это скорее хранилище объектов, чем фабрика, или это больше для класса, чем я вижу?

Если это хранилище объектов, то вы также можете найти дополнительное вдохновение в других вопросах, таких как этот .

1 голос
/ 21 декабря 2010

Просто зарегистрируйте тип классов, которые вы хотите создать, затем используйте Activator.CreateInstance для создания экземпляров этого типа.

Это должно работать следующим образом:

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;
}

Вы можете позвонить RegisterFeed следующим образом:

RegisterFeed(FeedType.SomethingSpecial, typeof(MyDerivedSpecialFeed));
1 голос
/ 21 декабря 2010

Когда вы вызываете метод RegisterFeed, вам нужно передать конкретный экземпляр класса Feed.Поэтому ответственность за конкретную реализацию лежит на вызывающей стороне.

0 голосов
/ 21 декабря 2010
class FeedFactory {


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

    }

}

Обратите внимание, что все каналы должны реализовать интерфейс IFeedFactory и реализовать необходимый метод.

// С клиента

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