Подтвердить что ты не робот

Каков ваш порог для использования factory вместо конструктора для создания объекта?

Каков ваш порог для использования factory вместо конструктора для создания объекта?

  • Вы всегда используете factory.
  • Вы используете фабрики только в том случае, если у вас есть инвариантные проверки, кроме проверки нулей.
  • Вы всегда используете конструкторы
  • Вы редко используете заводы... что это за дела?

плюсы и минусы

Обновление: я применяю шаблон factory из проекта Driven Design в моем проекте. И одной из причин создания заводов является снижение шума в модели домена.

Спасибо

4b9b3361

Ответ 1

Я использую factory, если у меня есть абстрактный базовый класс (или интерфейс) и несколько конкретных производных классов, и есть некоторая логика, согласно которой создается один из конкретных классов. Я реализую эту логику в factory.

Ответ 2

Наиболее очевидным для factory является случай, когда конкретный класс, реализующий интерфейс, будет выбран во время выполнения, например, из файла конфигурации. Я не очень активно использую фабрики, но когда я хочу, чтобы два объекта были сильно развязаны, я скорее всего использую factory для получения экземпляра другого.

Ответ 3

Что-то интересное в С#, относящееся к этой теме, заключается в том, что ограничение new() для общих типов, указанное в определении класса, заставляет типы, которые обрабатываются универсальным типом контейнера, реализовать конструктор без параметров. Ограничение new() необходимо только тогда, когда вы намереваетесь создать экземпляр типа T, как в GenericType<T>, внутри класса. Мне кажется, что это явно поддерживает кластерные фабрики, особенно фабрики, производящие типовые типы.

Чтобы включить это требование, Windows Communication Foundation (WCF) имеет класс ChannelFactory, который определяет следующий статический метод factory:

public static TChannel CreateChannel(Binding binding, EndpointAddress endpointAddress, Uri via)
{
    ChannelFactory<TChannel> factory = new ChannelFactory<TChannel>(binding);
    if (factory.HasDuplexOperations())
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxInvalidStaticOverloadCalledForDuplexChannelFactory1", new object[] { factory.channelType.Name })));
    }
    TChannel channel = factory.CreateChannel(endpointAddress, via);
    ChannelFactory<TChannel>.SetFactoryToAutoClose(channel);
    return channel;
}

Если вы посмотрите в Reflector при разборке класса (System.ServiceModel assembly и пространстве имен System.ServiceModel.Channels), вы заметите, что "new()" не используется в качестве ограничения.

Это потому, что метод CreateChannel использует typeof (TChannel) для делегирования создания объекта далее по цепочке...

public virtual TChannel CreateChannel(EndpointAddress address, Uri via)
{
    TChannel local;
    bool traceOpenAndClose = base.TraceOpenAndClose;
    try
    {
        using (ServiceModelActivity activity = (DiagnosticUtility.ShouldUseActivity && base.TraceOpenAndClose) ? ServiceModelActivity.CreateBoundedActivity() : null)
        {
            if (DiagnosticUtility.ShouldUseActivity)
            {
                ServiceModelActivity.Start(activity, this.OpenActivityName, this.OpenActivityType);
                base.TraceOpenAndClose = false;
            }
            if (address == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("address");
            }
            if (base.HasDuplexOperations())
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxCreateNonDuplexChannel1", new object[] { base.Endpoint.Contract.Name })));
            }
            base.EnsureOpened();
            local = (TChannel) this.ServiceChannelFactory.CreateChannel(typeof(TChannel), address, via);
        }
    }
    finally
    {
        base.TraceOpenAndClose = traceOpenAndClose;
    }
    return local;
}

Вы можете следить за цепочкой делегирования еще на несколько уровней, поскольку класс Type передается до тех пор, пока не будет вызван следующий метод:

RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);

Он чрезвычайно запутан, но это самый сложный factory, который я когда-либо видел. Интересно, что все махинации заканчиваются WCF, создающим класс RealProxy из пространства имен System.Runtime.Remoting.Proxies.

В заключение, фабрики предназначены для объектов, которые имеют большую сложность или нуждаются в построении динамического типа.

Ответ 4

Я не совсем уверен, как вы выбрали свои пороги...

Заводы подходят, если вы не хотите отвлекать потребителя от объекта из конструкции. Экземпляры, где это может быть уместным:

  • Вы можете отказаться от реализации во время выполнения. Часто это сочетается с использованием интерфейсов, а не конкретных классов. Примером в Java будет то, как вы получаете объект Document из DocumentBuilder в Java.
  • Вы можете ограничить количество экземпляров объекта. Подумайте о создании пула с ограниченным количеством объектов потока, а не просто созданием нового все время

Ознакомьтесь с книгой моделей Book of Four (Gamma et al.) и подробно рассмотрите шаблон factory для получения дополнительной информации о том, когда использовать этот шаблон.

Ответ 5

Здесь радикальная мысль (я не очень защищаю ее, но я не думаю, что это навредило бы):

Всегда используйте методы factory!

Factory методы более гибкие, например, они могут кэшировать результаты или возвращать дочерние классы.

Итак, вместо:

class SomeClass {
  public SomeClass(/*parameters*/) { /*...*/ }
} 

Всегда используйте:

class SomeClass {
  protected SomeClass(/*parameters*/) { /*...*/ }
  public static SomeClass New(/*parameters*/) {
    return new SomeClass(/*parameters*/);
  }
} 

Код вызывающего абонента изменяется с:

SomeClass sc = new SomeClass();

To:

SomeClass sc = SomeClass.New();

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

Ответ 6

Мне нравится поддерживать количество конструкторов до разумного низкого уровня; более двух или трех, и я задаю вопрос, насколько хорошо построена конструкция объекта.

В тех случаях, когда вводятся дополнительные конструкторы для поддержки различных необязательных атрибутов, мне нравится использовать Builder, как описано в Эффективная Java (Джошуа Блох, 2-е изд.)

Ответ 7

Я пытаюсь измерить между ними. Я думаю, что вы должны использовать фабрики, когда:

  • Большое количество параметров.
  • Необязательный параметр. (Оба используют внутренний шаблон Builder класса)
  • Вам придется изменить порядок параметров, чтобы выполнить другое действие из-за одних и тех же типов параметров, но разных данных.
  • Вам нужен одноэлементный класс (лучше сделать с перечислением)

На фабриках в этом случае вы можете дать правильное имя возвращаемому объекту.

Ответ 8

Используйте factory, когда решение о том, какой конкретный класс для создания экземпляра не подходит клиенту. например где существует несколько "семейств" объектов, и выбор того, какой семейство использовать, производится в другом месте.

Ответ 9

Я думаю, вы смешиваете шаблон Builder и шаблон Factory. Я бы предложил просто использовать конструкторы и сделать с ним. Похоже, что (не видя кода) вы слишком много думаете или слишком сильно разбираете свой код.