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:
AbstractProductAFactory
define a interface para produzir o ProductA. Suas implementações de concreto (ConcreteProductAFactory1, ConcreteProductAFactory2) a estenderiam.
AbstractProductBFactory
define 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.