Разницу будет легче увидеть с точки зрения клиентского класса, который использует фабричный класс.
Если клиентский класс использует конкретный фабричный класс, то будет сложно повторно использовать клиентский класс в другом контексте. Мы не можем заменить текущий используемый конкретный фабричный класс другим конкретным фабричным классом без изменения исходного кода клиентского класса.
Напротив, если клиент использует абстрактный класс (или интерфейс) фабрики, мы можем легко повторно использовать класс клиента с другим (конкретным) классом фабрики, поскольку в исходном коде класса клиента не упоминается какой-либо конкретный класс фабрики. Например, рассмотрим код ниже:
interface AbstractFactory { Product create(); }
class Client {
private AbstractFactory factory;
public Client(AbstractFactory factory) { this.factory = factory; }
public void foo() { /* use this.factory */ }
}
// Now we can reuse the Client class with any concrete factory class
class ConcreteFactory1 implements AbstractFactory { ... }
class ConcreteFactory2 implements AbstractFactory { ... }
Client client1 = new Client(new ConcreteFactory1());
client1.foo();
Client client2 = new Client(new ConcreteFactory2());
client2.foo();
Как видите, в любом случае исходный код класса Client
не нужно изменять, но он по-прежнему работает с другим конкретным классом фабрики.