2012-06-21 2 views
4

Вот как я обычно видеть шаблон Abstract Factory показано ниже:Abstract Factory Pattern - Точка бетонных заводов

public abstract class Factory 
{ 
    public abstract Product GetProduct(); 
} 

public class ConcreteFactory1 : Factory 
{ 
    public override Product GetProduct() { return new Product1(); } 
} 

class ConcreteFactory2 : Factory 
{ 
    public override Product GetProduct() { return new Product2(); } 
} 

interface Product 
{ 
    void SomeMethod(); 
} 

class Product1 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("1"); } 
} 

class Product2 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("2"); } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Factory f = null; 
     Product p = null; 
     switch (args[0]) 
     { 
      case "1": 
       f = new ConcreteFactory1(); 
       p = f.GetProduct(); 
       break; 
      case "2": 
       f = new ConcreteFactory2(); 
       p = f.GetProduct(); 
       break; 
     } 
     p.SomeMethod(); 
    } 
} 

Я обычно пишу это так, что не является истинной картины:

interface Product 
{ 
    void SomeMethod(); 
} 
class Product1 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("1"); } 
} 
class Product2 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("2"); } 
} 
public static class Factory 
{ 
    public static Product GetProduct(prodType) 
    { 
     Product p = null; 
     switch (prodType) 
     { 
      case "1": 
       p = new Product1(); 
       break; 
      case "2": 
       p = new Product2(); 
       break; 
     } 
     return p; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Product p = Factory.GetProduct(args[0]); 
     p.SomeMethod(); 
    } 
} 

Мой вопрос: в чем преимущество конкретных заводов? Я никогда не понимал смысла - кажется, это просто лишний лишний слой. Второй пример выглядит гораздо более кратким и простым.

+1

Я думаю, и исправьте меня, если я ошибаюсь, так это то, что обычно ваш код базового уровня не имеет понятия о конкретной используемой фабрике. Также не следует указывать тип продукта (в вашем случае) через 'prodType'. Вместо этого, конкретная реализация фабрики подается через некоторую форму инъекции зависимостей на ваш абстрактный завод, и ваш код продолжает веселиться, не имея понятия о том, какая фабрика используется, или о конкретных типах. Особенно, если эти конкретные заводские реализации предоставляются сторонними потребителями вашего API. –

+0

@Chris Точно. – Odrade

+0

Если у вас есть много продуктов, ваш единственный завод получит очень, очень большой. Если вы когда-либо решили сменить завод, на котором производится продукт, все ваши клиенты должны будут измениться, поскольку завод не будет отвлекаться от них. Они имеют прямую ссылку на ваш единственный завод. – dash

ответ

6

С Одрадом согласен со мной (думает, я не совсем с моим рокером) я выложу это как ответ:

Я думаю, и поправьте меня, если я ошибаюсь, это нормально своей база код уровня не имеет понятия о конкретной используемой фабрике. Также не следует указывать тип продукта (в вашем случае) через prodType. Вместо этого, конкретная реализация фабрики подается через некоторую форму инъекции зависимостей на ваш абстрактный завод, и ваш код продолжает веселиться, не имея понятия о том, какая фабрика используется, или о конкретных типах. Особенно, если эти конкретные заводские реализации предоставляются сторонними потребителями вашего API.

В статье Википедии о нем дает достойный пример в отношении операционной системы GUI строительств: http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23

По сути, ваш код, в библиотеке может функционировать нормально, не зная, какие детали реализации или зависимости от используемой операционной системы. Когда вы (или пользователь вашего API) переходите к переходу на Linux (в этом примере в Википедии), вы просто реализуете LinuxFactory и LinuxButton и загружаете их в свой API. Если вместо того, чтобы, как в вашем типичном примере, вы контролируете его через вход, скажем, перечисление, то ваш завод должен знать о Linux:

public static class Factory 
{ 
    public static Button GetButton(operatingSystem) 
    { 
     switch (operatingSystem) 
     { 
      case "windows": 
       return new WindowsButton(); 
      case "macintosh": 
       return new MacButton(); 
     } 
    } 
} 

Как Linux получить корректироваться сейчас? Ну это не может, если вы добавьте поддержку. Плюс теперь все потребители вашего API косвенно зависят от всех реализаций операционной системы.

EDIT: Обратите внимание, что Factory Pattern и Abstract Factory Pattern - это две совершенно разные концепции. Что касается ваших проблем с тем, почему вы задавали вопрос в первую очередь, абстрактные шаблоны фабрик не всегда необходимы. Если вам это не нужно, то не добавляйте сложность одного. Если вам просто нужна простая фабрика (какой ваш второй пример является вариантом), то используйте ее. Правильный инструмент для правильной работы и всего этого.

+1

Согласитесь; хороший ответ +1. – dash

+1

+1; хороший ответ. Я хотел бы подчеркнуть, что вопрос о том, нужен ли шаблон. Я считаю, что распространенная ошибка заключается в том, что, поскольку один образец более развит, чем другой, он как-то «лучше». Это не так - это больше подходит для конкретного сценария, который требует большей сложности. Если у вас нет сложных требований, которые удовлетворяет шаблон, используйте более простой подход. Шаблоны - это просто руководства к решениям, которые работают на разных уровнях программного обеспечения, каждый из которых имеет преимущества и обязательства. Ваши конкретные потребности будут опосредованы каждой выплатой. – codekaizen

+0

Я с тобой. И, кажется, мой первый пример - абстрактная фабрика, и они, как я предпочитаю делать что-то, это шаблон Factory. Кажется, мне обычно больше нужна фабрика. – user210757

2

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

0

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

завода (в общем случае - фабричный метод, Abstract Factory и т.д.), используемый для решения сложного создающего типа объекта, если ваш Product1 и Product2 требуют другой тип инициализации, тогда не будет хорошей идеей жестко записать его на вашем конкретном заводе.

1

«Абстрактная фабрика» действительно плохое имя для этого шаблона. Гораздо лучше назвать шаблон «Kit», который также использовал GoF. Я согласен, в примере, который вы дали, это чрезмерный дизайн.это имеет гораздо больший смысл, когда ваши заводы несут ответственность за создание множества объектов, которые работают вместе. Затем различные группы из них (наборы, если хотите) создаются на разных фабриках, в соответствии с заданным набором условий выполнения или времени разработки.

This is a really good article about it. Там не-программная аналогия метрических и английских наборов гнезд идеальна.