抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式通过封装一组工厂,该工厂有通用的没有指定它们具体类的主题。在通常的用法中,客户端软件创建一个实现了抽象工厂的具体类然后使用通用的工厂接口去创建某一主题的具体类。客户端并不知道从工厂里获取的是哪一个具体类,因为它仅使用通用的接口。该模式将通用接口与其一系列对象的实现以及对对象的依赖分离开来。
具体实现类在工厂中构造,目的是将对象的创建与对象的使用场景相隔离,以便创建一系列相关联的家族类而不依赖其实现的具体类。这样的好处是,当产生新的继承类时,而无需修改使用它们基类处的代码。
抽象工厂模式可以无需修改使用处的代码便可以替换具体类,甚至在运行时也可以这么做。然而,运用这种模式,与它相似的设计模式一样,会带来不必要的复杂度和初始化时额外的工作。另外,高度的分离和抽象会使代码调试和维护变得困难。
抽象工厂模式描述如何解决设计灵活性和复用性中的常见问题,即对象可以被方便地是实现、改变、测试和复用。
抽象工厂模式解决如下问题:
应用的对象如何创建?
一个类所需的对象的创建怎样依赖这个类?
一系列相关的或相互依赖的对象如何创建?
在一个类中直接创建其所需要的类是不灵活的,因为这样会使类绑定特定的对象,今后如果要更改实例也是不可能的。当类需要其他的特定对象时,将变得不可重用。这也将导致该类测试起来比较困难,因为在模拟对象中无法替换实际对象。
抽象工厂模式描述了怎样解决这些问题:
- 封装对象的创建在一个分离的对象(工厂)中,即,定义一个接口(抽象工厂)用于创建对象,并实现该接口。
- 一个类将其创建委托给工厂对象而不是直接创建。
这使一个类独立于其创建的过程。一个工厂对象中可配置一个甚至更多的类,工厂对象在运行时可以被替换。
读者可以看下面的UML类和序列图。
定义
抽象工厂的本质是“提供一个接口用于创建一系列关联对象或依赖对象而无需指定具体类”。
用法:
工厂决定当前将要被创建的具体类类型,且这些对象在工厂中创建,然而,工厂仅仅返回抽象类来引用被创建的具体对象。
作为工厂仅返回抽象类,客户端代码并不知道是哪一个具体类被创建,而抽象工厂是知道的。例如,抽象工厂可以从配置文件中获取。客户端无需指定具体对象,因为在抽象工厂的配置文件中已经指定了,特别是:
- 客户端代码没有任何具体类的信息,无需包括其定义。客户端代码仅仅处理抽象类型。具体类的对象是被工厂创建,但是客户端代码访问具体类对象仅通过抽象接口。
- 增加一种新的具体类时,客户端代码仅需要使用不同的工厂,修改通常在一个文件中的一行代码。不同的工厂创建不同的具体类对象,但是仍然返回抽象类型的引用。这样就隔离了客户端代码与具体类的变化。这要比修改一个具体类就要修改客户端代码好得多,否则就要修改每一处创建新具体类对象的地方。如果所有的工厂定义为全局的单例对象,并且所有的客户端代码通过这个单例去访问适当的工厂去创建对象,那么修改工厂和修改具体类也是同样方便的了。
为形状创建一个接口。
Shape.java
public interface Shape {
void draw();
}
创建实现接口的实体类。
Rectangle.java public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }
Square.java public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } }
Circle.java
public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }
为颜色创建一个接口。
Color.java
public interface Color {
void fill();
}
创建实现接口的实体类。
Red.java
public class Red implements Color { @Override public void fill() { System.out.println("Inside Red::fill() method."); } }
Green.java
public class Green implements Color { @Override public void fill() { System.out.println("Inside Green::fill() method."); } }
Blue.java
public class Blue implements Color {
@Override
public void fill() {
System.out.println("Inside Blue::fill() method.");
}
}
为 Color 和 Shape 对象创建抽象类来获取工厂。
AbstractFactory.java
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。
ShapeFactory.java
public class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null;
}
}
ColorFactory.java
public class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
public Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
FactoryProducer.java
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
Shape shape1 = shapeFactory.getShape("CIRCLE");
shape1.draw();
Shape shape2 = shapeFactory.getShape("RECTANGLE");
shape2.draw();
Shape shape3 = shapeFactory.getShape("SQUARE");
shape3.draw();
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
Color color1 = colorFactory.getColor("RED");
color1.fill();
Color color2 = colorFactory.getColor("Green");
color2.fill();
Color color3 = colorFactory.getColor("BLUE");
color3.fill();
}
}