O Abstract Abstract Pattern é dimensionado?

8

Ainda estou tentando entender os padrões de design aqui, depois de aprender o padrão abstrato de fábrica, percebi que esse padrão não será dimensionado bem. Dê uma olhada no diagrama uml do padrão abstrato de fábrica

diagrama uml

Se eu tiver que criar um novo 'AbstractProductC', terei que adicionar um método abstrato 'CreateProductC' em 'AbstractFactory', que afeta a implementação do ConcreateFactory1, ConcreateFactory2.

Minha pergunta aqui é: o padrão Abstract Factory é escalado de alguma forma (ou) eu estou pensando na direção errada aqui?

desde já, obrigado

Jitendar
fonte
Eu acho que o diagrama que você apresentou, que parece relativamente padrão, foi simplificado para ilustrar o padrão em questão. No entanto, se você precisar de algo mais complexo, o AbstractFactory sempre poderá definir apenas um método: CreateProduct (productType) e, em seguida, ter uma fábrica dentro de uma fábrica que analise o tipo e instale a classe concreta com base nisso.
DXM
@ DXM Isso não resolve o problema. Você ainda precisará alterar a implementação de fábricas concretas sempre que adicionar um novo produto.
Euphoric
Bem, a única coisa que poderia ser dimensionada é a interface abstrata real, mas sim, se você tiver N produtos e M maneiras de criá-los, não importa como você o fatie, precisará de implementações N x M, a menos que siga uma estratégia completamente diferente .
DXM
@Euphoric: Não necessariamente. Você poderia apenas adicionar uma classe de fábrica e registrá-la na fábrica abstrata. Pode parecer um pouco complicado, mas para o dimensionamento e SRP, acho que adicionar um pouco menos problemático do que mudar.
Marjan Venema
@MarjanVenema Agora, a questão é se é realmente uma fábrica e não um padrão diferente.
Euphoric

Respostas:

5

Abstract Factory escala muito bem.

Existe um princípio básico que afirma que uma classe deve fazer uma coisa bem. Seu problema aqui é que você está tentando fazer com que muitas classes façam muitas coisas.

Você não precisa se ater a uma fábrica abstrata. Você pode (e deve ter) vários:

AbstractProductAFactorydefine a interface para produzir o ProductA. Suas implementações de concreto (ConcreteProductAFactory1, ConcreteProductAFactory2) a estenderiam.

AbstractProductBFactorydefine a interface para produzir o ProductB. Suas implementações concretas ( ConcreteProductBFactory1, ConcreteProductBFactory2) a estenderiam.

Se você precisar de um ProductC, crie um novo AbstractProductCFactory. Não é necessário alterar nenhuma de suas outras fábricas dessa maneira.

ATUALIZAÇÃO Idealmente, o ProductA deve representar uma classe de produto - ou seja, todos os produtos que compartilham uma interface que você está chamando de ProductA. Nos comentários, sugiro que isso é algo como uma Pizza:

interface AbstractPizzaFactory {
    public Pizza buildPizza(List<Topping> toppings);
}


class ThinCrustPizzaFactory implements AbstractPizzaFactory {
    public Pizza buildPizza(List<Topping> toppings){

        ...

    }
}

class DeepDishPizzaFactory implements AbstractPizzaFactory {
    public Pizza buildPizza(List<Topping> toppings){

        ...

    }
}

E assim por diante. Adicionar um PanPizzaFactory não afetará nenhuma das outras classes - é apenas uma nova implementação concreta do PizzaFactory. Se você tem produtos que não são pizzas - sanduíches, por exemplo, é aí que você cria outra fábrica abstrata (por exemplo, AbstractSandwichFactory).

O ponto real é que você não gostaria de ter uma fábrica abstrata que constrói dois tipos muito diferentes de produto com dois métodos diferentes de "construção". Agrupe-os da maneira mais lógica possível, para que eles compartilhem uma interface e, em seguida, crie uma fábrica abstrata que defina como fábricas concretas devem construir implementações dessa interface.

Matthew Flynn
fonte
4
Ta brincando né? E se sua empresa produz 256 produtos? Ou 1024?
Robert Harvey
@RobertHarvey - Estou assumindo que ProductA é uma classe de produtos - suponha que seja um AbstractPizzaFactory. Isso pode ter um ThinCrustPizzaFactory concreto, um PanPizzaFactory concreto e um DeepDishPizzaFactory concreto. Da mesma forma, os sanduíches seriam construídos pelos subtipos de uma AbstractSandwichFactory. Isso é diferente de e AgrstractFactory com os métodos buildPizza e buildSandwich.
Matthew Flynn
@RobertHarvey - Enquanto isso, variações sutis em produtos (como coberturas) podem ser algo que pode ser tratado separadamente. Talvez o seu método de fábrica seria AbstractPizzaFactory.buildPizza(List<Topping> toppings).
Matthew Flynn
Você pode deixar essas coisas claras em sua resposta.
Robert Harvey
@RobertHarvey - atualizado
Matthew Flynn
4

O problema com a escala é que o código pode ser escalado de várias maneiras diferentes. O problema que você está enfrentando é simplesmente causado pela necessidade de escalar em uma direção, para o qual o padrão de design não se destina. No caso do padrão Abstract Factory, ele deve ser dimensionado de forma a adicionar novas fábricas de concreto, mas adicionar novos produtos causa grandes mudanças estruturais.

Um dos pontos do design e da arquitetura de software é identificar as direções mais prováveis ​​para o código escalar e escolher padrões com base nessas direções prováveis. Se você identificar que a adição de um novo produto é mais provável do que a adição de uma nova fábrica de concreto, usar a Abstract Factory não é uma boa ideia e pode ser melhor repensar completamente o design.

Eufórico
fonte
1
sua resposta faz mais sentido do que as rígidas "ESCALAS ABSTRATAS DA FÁBRICA!" do outro cara ...
Turkish
@Euphoric, como você está sugerindo, a escala abstrata de padrões de fábrica é uma maneira de adicionar novas fábricas de concreto, mas finalmente a nova fábrica de concreto precisa gerar produtos, que se resumem à criação do produto e, finalmente, devemos fazer mudanças estruturais, não é direita?
Jitendar
@Jitendar Não entendo o que você quer dizer. O ponto da fábrica abstrata é que existe uma família relativamente estável de abstrações relacionadas (Produto A, Produto B) e fábricas concretas criam implementações dessas abstrações, que também estão relacionadas de alguma forma. Se a possibilidade de adicionar nova abstração for maior do que adicionar novas implementações concretas dessas abstrações, usar o Abstract Factory não é uma boa escolha.
Euphoric
3

Sim, você está certo, a "fábrica abstrata" não se adapta bem quando você precisa de produtos abstratos adicionais .

Mas em muitos cenários do mundo real, você tem um número variável de produtos, mas apenas um número pequeno e fixo de produtos abstratos para oferecer suporte. Por exemplo, veja o exemplo de widgets da GUI no artigo da Wikipedia sobre fábricas abstratas . A fábrica abstrata da GUI poderia ter um método createWidget(em vez de createButton), onde Widgeté o "produto abstrato", sendo a classe base mais alta para uma família de várias dezenas de elementos da GUI. A adição de novos widgets da GUI não implica em nenhuma alteração na interface da fábrica abstrata, portanto, nenhuma das interfaces da fábrica de concreto precisa ser alterada.

Ter muitos produtos abstratos significa que você terá várias hierarquias de classe diferentes no seu código. E se for esse o caso, considere criar uma fábrica individual (ou fábrica abstrata) para cada uma das hierarquias.

Doc Brown
fonte
0

Seu fator de escala é uma questão simples de gerenciamento de dependências. Quanto mais dependências uma classe tiver - mais estável e ponderada deverá ser sua API.

Não há problema em criar uma fábrica definida pela responsabilidade de criar tipos de natureza semelhante ou coesa. Mas quanto mais classes dependem dessa fábrica - mais estrita deve ser essa coesão.

(Nota: isso pode ser feito de forma gradual, não necessariamente por um BDUF)

Yam Marcovic
fonte