介绍
抽象工厂设计模式是创造模式的一种。抽象工厂模式几乎类似于工厂模式,被认为是对工厂模式的另一层抽象。抽象工厂模式围绕创建其他工厂的超级工厂工作。
抽象工厂模式实现为我们提供了一个框架,允许我们创建遵循通用模式的对象。因此,在运行时,抽象工厂与任何可以创建所需类型对象的具体工厂相结合。
让我们看看抽象工厂模式的 GOF 表示:
抽象工厂设计模式的 UML 类图示例。
- AbstractFactory :为创建抽象产品对象的操作声明一个接口。
- ConcreteFactory :实现在 AbstractFactory 中声明的操作以创建具体的产品对象。
- Product :定义了一个由相应的具体工厂创建的产品对象,并实现了 AbstractProduct 接口。
- Client :仅使用 AbstractFactory 和 AbstractProduct 类声明的接口。
抽象工厂提供了用于创建相关或依赖对象系列的接口,而无需指定它们的具体类。
客户端软件创建抽象工厂的具体实现,然后使用通用接口创建属于对象系列的具体对象。
客户端不知道也不关心它从每个具体工厂中获得哪些具体对象,因为它只使用其产品的通用接口。
因此,有了抽象工厂模式的这个想法,我们现在将尝试创建一个有助于创建相关对象的设计。
执行
举个例子,假设我们要建立一个全球汽车工厂。如果是工厂设计模式,那么它适用于单一位置。但是对于这种模式,我们需要多个位置和一些关键的设计更改。
我们需要每个地方的汽车工厂,如 IndiaCarFactory、USACarFactory 和 DefaultCarFactory。现在,我们的应用程序应该足够智能,可以识别使用它的位置,因此我们应该能够使用合适的汽车工厂,甚至不知道将在内部使用哪个汽车工厂实现。这也使我们免于有人为特定位置调用错误的工厂。
在这里,我们需要另一层抽象来识别位置并在内部使用正确的汽车工厂实现,而无需向用户提供任何提示。这正是抽象工厂模式用来解决的问题。
// Java Program to demonstrate the
// working of Abstract Factory Pattern
enum CarType
{
MICRO, MINI, LUXURY
}
abstract class Car
{
Car(CarType model, Location location)
{
this.model = model;
this.location = location;
}
abstract void construct();
CarType model = null;
Location location = null;
CarType getModel()
{
return model;
}
void setModel(CarType model)
{
this.model = model;
}
Location getLocation()
{
return location;
}
void setLocation(Location location)
{
this.location = location;
}
@Override
public String toString()
{
return "CarModel - "+model + " located in "+location;
}
}
class LuxuryCar extends Car
{
LuxuryCar(Location location)
{
super(CarType.LUXURY, location);
construct();
}
@Override
protected void construct()
{
System.out.println("Connecting to luxury car");
}
}
class MicroCar extends Car
{
MicroCar(Location location)
{
super(CarType.MICRO, location);
construct();
}
@Override
protected void construct()
{
System.out.println("Connecting to Micro Car ");
}
}
class MiniCar extends Car
{
MiniCar(Location location)
{
super(CarType.MINI,location );
construct();
}
@Override
void construct()
{
System.out.println("Connecting to Mini car");
}
}
enum Location
{
DEFAULT, USA, INDIA
}
class INDIACarFactory
{
static Car buildCar(CarType model)
{
Car car = null;
switch (model)
{
case MICRO:
car = new MicroCar(Location.INDIA);
break;
case MINI:
car = new MiniCar(Location.INDIA);
break;
case LUXURY:
car = new LuxuryCar(Location.INDIA);
break;
default:
break;
}
return car;
}
}
class DefaultCarFactory
{
public static Car buildCar(CarType model)
{
Car car = null;
switch (model)
{
case MICRO:
car = new MicroCar(Location.DEFAULT);
break;
case MINI:
car = new MiniCar(Location.DEFAULT);
break;
case LUXURY:
car = new LuxuryCar(Location.DEFAULT);
break;
default:
break;
}
return car;
}
}
class USACarFactory
{
public static Car buildCar(CarType model)
{
Car car = null;
switch (model)
{
case MICRO:
car = new MicroCar(Location.USA);
break;
case MINI:
car = new MiniCar(Location.USA);
break;
case LUXURY:
car = new LuxuryCar(Location.USA);
break;
default:
break;
}
return car;
}
}
class CarFactory
{
private CarFactory()
{
}
public static Car buildCar(CarType type)
{
Car car = null;
// We can add any GPS Function here which
// read location property somewhere from configuration
// and use location specific car factory
// Currently I'm just using INDIA as Location
Location location = Location.INDIA;
switch(location)
{
case USA:
car = USACarFactory.buildCar(type);
break;
case INDIA:
car = INDIACarFactory.buildCar(type);
break;
default:
car = DefaultCarFactory.buildCar(type);
}
return car;
}
}
class AbstractDesign
{
public static void main(String[] args)
{
System.out.println(CarFactory.buildCar(CarType.MICRO));
System.out.println(CarFactory.buildCar(CarType.MINI));
System.out.println(CarFactory.buildCar(CarType.LUXURY));
}
}
输出 :
Connecting to Micro Car
CarModel - MICRO located in INDIA
Connecting to Mini car
CarModel - MINI located in INDIA
Connecting to luxury car
CarModel - LUXURY located in INDIA
区别
- “工厂方法”和“抽象工厂”的主要区别在于工厂方法是单个方法,抽象工厂是一个对象。
- 工厂方法只是一个方法,它可以在子类中被覆盖,而抽象工厂是一个具有多个工厂方法的对象。
- 工厂方法模式使用继承并依赖子类来处理所需的对象实例化。
好处
当客户端不确切知道要创建什么类型时,此模式特别有用。
- 具体类的隔离:抽象工厂模式可帮助您控制应用程序创建的对象类。由于工厂封装了创建产品对象的职责和过程,因此它将客户与实现类隔离开来。客户端通过它们的抽象接口操作实例。产品类名在具体工厂的实现中是隔离的;它们不会出现在客户端代码中。
- 轻松交换产品系列:具体工厂的类在应用程序中只出现一次,也就是它被实例化的地方。这使得更改应用程序使用的具体工厂变得容易。只需更换混凝土工厂即可使用各种产品配置。由于抽象工厂创建了完整的产品系列,因此整个产品系列会立即发生变化。
- 促进产品之间的一致性:当一个系列中的产品对象设计为协同工作时,应用程序一次只使用一个系列的对象很重要。 AbstractFactory 使这很容易执行。
缺点
- 难以支持新型产品:扩展抽象工厂以生产新型产品并不容易。那是因为 AbstractFactory 接口修复了可以创建的产品集。支持新类型的产品需要扩展工厂接口,这涉及更改 AbstractFactory 类及其所有子类。
笔记 :
在某种程度上,上面的例子也是基于像 uber 和 ola 这样的出租车如何大规模运作的。