工厂模式:
// 抽象产品接口
interface Product {
void showInfo();
}
// 具体产品A
class ConcreteProductA implements Product {
@Override
public void showInfo() {
System.out.println("This is Product A");
}
}
// 具体产品B
class ConcreteProductB implements Product {
@Override
public void showInfo() {
System.out.println("This is Product B");
}
}
// 抽象工厂类
abstract class Creator {
abstract Product createProduct();
}
// 具体工厂A,生产产品A
class ConcreteCreatorA extends Creator {
@Override
Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂B,生产产品B
class ConcreteCreatorB extends Creator {
@Override
Product createProduct() {
return new ConcreteProductB();
}
}
public class FactoryMethodExample {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.createProduct();
productA.showInfo();
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.createProduct();
productB.showInfo();
}
}
在这个示例中,Product
是抽象产品接口,ConcreteProductA
和 ConcreteProductB
是具体的产品类。Creator
是抽象工厂类,ConcreteCreatorA
和 ConcreteCreatorB
是具体的工厂类,分别生产不同的产品。在场景类中,通过具体的工厂来创建不同的产品,而无需直接涉及具体产品的实现类。这就是工厂方法模式的正确用法。
抽象工厂模式:
// 抽象产品接口
interface ProductA {
void showInfo();
}
// 具体产品A1
class ConcreteProductA1 implements ProductA {
@Override
public void showInfo() {
System.out.println("This is Product A1");
}
}
// 具体产品A2
class ConcreteProductA2 implements ProductA {
@Override
public void showInfo() {
System.out.println("This is Product A2");
}
}
// 抽象产品接口
interface ProductB {
void showInfo();
}
// 具体产品B1
class ConcreteProductB1 implements ProductB {
@Override
public void showInfo() {
System.out.println("This is Product B1");
}
}
// 具体产品B2
class ConcreteProductB2 implements ProductB {
@Override
public void showInfo() {
System.out.println("This is Product B2");
}
}
// 抽象工厂接口
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
public class AbstractFactoryExample {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
productA1.showInfo();
productB1.showInfo();
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.showInfo();
productB2.showInfo();
}
}
在这个示例中,AbstractFactory
是抽象工厂接口,ConcreteFactory1
和 ConcreteFactory2
是具体工厂类,分别生产不同系列的产品。每个具体工厂类实现了创建一组相关产品的方法。这就是抽象工厂模式的示例。
区别:
抽象工厂模式(Abstract Factory Pattern)和工厂方法模式(Factory Method Pattern)是两种不同的设计模式,它们都属于创建型模式,用于创建对象。它们之间的区别在于抽象程度和用途。
-
抽象工厂模式:
- 抽象工厂模式用于创建一组相关或相互依赖的对象,这些对象通常属于不同的产品族。
- 它包含一个抽象工厂接口,该接口声明了一组用于创建不同类型产品的抽象方法。每个具体工厂类实现了这些方法以创建特定产品族的对象。
- 抽象工厂模式强调创建一组对象,通常涉及多个产品接口和多个产品实现类。
-
工厂方法模式:
- 工厂方法模式用于创建单一对象,但是通过子类来决定实例化哪个类。
- 它包含一个抽象工厂基类(接口或抽象类),该基类声明了一个用于创建对象的抽象方法。每个具体工厂子类实现这个方法以返回特定的产品对象。
- 工厂方法模式强调创建单一对象,每个工厂子类负责创建一种产品。
总结:
抽象工厂模式关注于一组相互关联的产品,而工厂方法模式关注于单一产品。抽象工厂模式的实现可能比较复杂,涉及多个产品族,而工厂方法模式通常相对简单,每个子类只负责一个产品。选择哪个模式取决于需求的复杂性和结构的设计。
抽象工厂模式在工厂模式的基础上扩展了一个维度,不仅关注单一产品的创建,还关注一组相关或相互依赖的产品族的创建。这些产品族通常在业务逻辑上有关联,它们可能共同构成一个完整的功能。
缺点总结:
在抽象工厂模式中,如果你想要增加一个新的产品,比如产品C,你需要在抽象工厂接口(或抽象类)中添加一个新的方法来创建该产品。然后,所有的具体工厂类都必须实现这个新方法,为产品C提供实现。这会导致两个问题:
-
修改抽象类或接口: 在这个例子中,你需要在
AbstractCreator
中增加一个createProductC()
方法,并且ConcreteFactory1 和ConcreteFactory2都必须实现这个方法。这违反了开闭原则,即系统应该对扩展开放,对修改关闭。 -
影响已有代码: 增加新方法会影响到所有已经实现了该抽象工厂的具体工厂类,即ConcreteFactory1 和ConcreteFactory2。这可能会导致许多现有的代码需要修改,因此它们与这个变化产生了依赖关系,即所谓的“有毒代码”。
这种情况下,每次需要增加一个新的产品时,都会引发一系列的修改,从而导致系统的脆弱性和不稳定性。这就是抽象工厂模式的一个局限性,特别是当产品族的变化比较频繁时,扩展性不如其他设计模式。
这也是为什么有时候推荐使用工厂方法模式,因为它对于新增产品更具有弹性,不会对已有的代码造成较大的影响。但抽象工厂模式的优势在于它能够同时创建一组相关的产品,适用于需要创建一组具有特定关联性的对象的情况。
但是也有优点,在添加新的产品族时,只需要新增对应的产品接口和实现,而不需要修改已有的工厂类和产品类。这符合开闭原则,允许易于扩展而不影响现有代码。