Использование фабричного или строительного образца с неуниверсальным классом продукта? - PullRequest
1 голос
/ 21 сентября 2011

Добрый день.

Я пытаюсь выяснить, какой шаблон я могу использовать для какой-то новой разработки, но я увязаю. Сначала я подумал о фабричном образце, но потом, возможно, о строителе, но ни один из них, похоже, не подходит идеально.

Моя проблема в том, что базовый класс Product в шаблонах не является универсальным. Кажется, что для всех шаблонов Factory и Builder базовые продукты должны быть абсолютно одинаковыми.

Например, (очень глупый пример):

public class ProductBase
{
    public int x;
    public int y;
}

public class ProductA : ProductBase
{
    public int z;
}

public class ProductB : ProductBase
{
    public int a;
}

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

В любом случае, любые указания относительно того, какой подход здесь может быть принят, приветствуются. В конечном счете, я ищу некоторую модификацию этих шаблонов (или совсем другую) для учета неуниверсальных продуктов. Или, может быть, настройка специфических для типа данных для продукта после создания по шаблону не так уж и плоха?

ОБНОВЛЕНИЕ: я должен был упомянуть, что мне нужно установить специфичные для типа данные (z или a) во время выполнения, так как они передаются через веб-форму. Таким образом, я не могу оставить это на усмотрение Фабрики или Строителя для создания полного экземпляра, мне все еще нужен какой-то способ установки данных после факта (или во время создания экземпляра, но, похоже, это не имеет хорошего общего решения).

Ответы [ 2 ]

1 голос
/ 21 сентября 2011

Что плохого в том, чтобы иметь один абстрактный класс фабричного метода и один конкретный фабричный метод для каждого продукта?

public class ProductBase
{
    public int x;
    public int y;
}

public class ProductA : ProductBase
{
    public int z;
}

public class ProductB : ProductBase
{
    public int a;
}
public class Factory
{
    abstract Product Create();
}
public class FactoryA:Factory
{
    override Product Create()
    {
         return new ProductA();
    }
}
public class FactoryB:Factory
{
    override Product Create()
    {
       return new ProductB();
    }
}

Это для общего случая и внешнего параметра.

 internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
            var fact = new FactoryA();
            int passParam = 5;//fromGUI
            ProductA f = fact.Create(passParam);
        }
    }

    public class ProductBase
    {
        public int x;
        public int y;
    }

    public class ProductA : ProductBase
    {
        public int z;
    }

    public class ProductB : ProductBase
    {
        public int a;
    }

    public abstract class Factory<T> where T : ProductBase
    {
        public abstract T Create(int passedParam);
    }

    public class FactoryA : Factory<ProductA>
    {
        public override ProductA Create(int passedParam)
        {
            return new ProductA() { x = 1, y = 1, z = passedParam };
        }
    }

    public class FactoryB : Factory<ProductB>
    {
        public override ProductB Create(int passedParam)
        {
            return new ProductB() { x = 1, y = 1, a = passedParam };
        }
    }
0 голосов
/ 21 сентября 2011

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

Если вы чувствуете, что процесс строительства слишком сложен, его можно модульно модифицировать:

class ProductFactoryBase {
  protected void Populate(ProductBase p) {
    p.x = some_x;
    p.y = some_y;
  }
}

class ProductAFactory : ProductFactoryBase {
  public ProductBase Create() {
    ProductA p = new ProductA();
    populate(p);
    p.z = some_z;
    return p;
  }
}

class ProductBFactory : ProductFactoryBase {
  public ProductBase Create() {
    ProductB p = new ProductB();
    populate(p);
    p.a = some_a;
    return p;
  }
}

class ProductFactory {
  private ProductAFactory paf = new ProductAFactory();
  private ProductBFactory pbf = new ProductBFactory();

  ProductBase Create(bool create_A) {
    if ( create_A )
      return paf.Create();
    else
      return pbf.Create();
  }
}

Однако, если вам не нужно использовать ProductA s и ProductB s, как если бы они были одним и тем же, не обобщайте просто ради этого;просто создавайте и используйте экземпляры каждого типа, когда они вам нужны.

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

Надеюсь, это ответит на ваш вопрос.

...