抽象工厂模式
抽象工厂模式是什么
- 抽象工厂模式
属于创建型模式
,是对工厂的一种抽象,可以理解为生产工厂的总工厂,不但工厂是抽象的,并且产品也是抽象的,而且会有多个产品需要创建,因此这个抽象工厂会对应多个实际工厂,每个实际工厂负责创建多个实际产品。 - 他有两个维度
产品簇
,产品等级
- 产品族:产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,就好比是一个品牌下的所有产品,如华为下面的手机、电脑、路由器都被称为是华为的产品族。
- 产品等级:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有各种品牌的电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品登记结构,抽象电视机是父类,而具体品牌的电视机是其子类。
抽象工厂方法模式
- 这种模式是在原先的层级上多加了一层 实现的效果就是,不由原先的工厂类来实例对象工厂父类来定义创建产品的公共接口, 而各工厂子类对象通过集成来实现这个创建接口, 在这个实现里面去完成究竟应该实例化哪一个具体产品,这样就可以在不影响原先种类的情况下引入新的产品。
- 示意图如下
- 如图所示 一个具体工厂要实现一整个产品族的创建
- 每一个具体工厂可以生产属于一个产品族的所有产品,例如生产颜色相同的正方形、圆形和椭圆形,所生产的产品又位于不同的产品等级结构中。如果使用工厂方法模式,图所示结构需要提供15个具体工厂,而使用抽象工厂模式只需要提供5个具体工厂,极大减少了系统中类的个数。
抽象工厂结构图
- 其中Factory扮演工厂的抽象角色,在它中规定了两个抽象方法,这两个方法分别是创建产品A和产品B的抽象方法。然后图中的Factory1与Factory2就是实现Factory的具体工厂类,他们在各自的实现方法内来创建自己对应族的实体类。
代码实例
- 在这个代码实例中,我们将模拟各地风味小吃店订单,有兰州的小吃店中有适合国人的牛肉面和牛肉披
- 我们先定义pizza的接口与面的接口
interface IPizzaProduct {
//准备材料`
void material();
void bake();
void cut();
void box();
}
interface INoodles {
//准备材料`
void material();
void cook();
void box();
}
- 定义他们的四个实现类
class CheesePizza implements IPizzaProduct {
String pizzaName = "芝士";
CheesePizza() {
this.pizzaName = this.pizzaName + "披萨";
}
//准备材料
public void material() {
System.out.println("正在准备芝士披萨的材料");
}
public void bake() {
System.out.println("正在烤 " + this.pizzaName);
}
public void cut() {
System.out.println("正在切 " + this.pizzaName);
}
public void box() {
System.out.println("正在打包 " + this.pizzaName);
}
}
class BeefPizza implements IPizzaProduct {
String pizzaName = "牛肉";
BeefPizza() {
this.pizzaName = this.pizzaName + "披萨";
}
//准备材料
public void material() {
System.out.println("正在准备牛肉披萨的材料");
}
public void bake() {
System.out.println("正在烤 " + this.pizzaName);
}
public void cut() {
System.out.println("正在切 " + this.pizzaName);
}
public void box() {
System.out.println("正在打包 " + this.pizzaName);
}
}
class BeefNoodles implements INoodles {
private String noodleName = "牛肉面";
@Override
public void material() {
System.out.println("正在准备" + noodleName + "所需材料");
}
@Override
public void cook() {
System.out.println("正在煮" + noodleName);
}
@Override
public void box() {
System.out.println("正在打包" + noodleName);
}
}
class VegetableNoodles implements INoodles {
private String noodleName = "青菜面";
@Override
public void material() {
System.out.println("正在准备" + noodleName + "所需材料");
}
@Override
public void cook() {
System.out.println("正在煮" + noodleName);
}
@Override
public void box() {
System.out.println("正在打包" + noodleName);
}
}
- 定义抽象工厂类
interface IProductFactory {
//制作pizza
IPizzaProduct pizzaProduct();
//制作noodles
INoodles noddlesProduct();
}
- 伦敦小吃店和兰州小吃店实现类,继承工厂接口
//定义具体工厂来继承工厂接口
class LanzhouFactory implements IProductFactory{
@Override
public IPizzaProduct pizzaProduct() {
return new BeefPizza();
}
@Override
public INoodles noddlesProduct() {
return new BeefNoodles();
}
}
class LDFactory implements IProductFactory{
@Override
public IPizzaProduct pizzaProduct() {
return new CheesePizza();
}
@Override
public INoodles noddlesProduct() {
return new VegetableNoodles();
}
}
- 在主函数中尝试调用工厂创建具体的产品
public static void main(String[] args) {
LDFactory ldFactory = new LDFactory();
INoodles iNoodles = ldFactory.noddlesProduct();
iNoodles.material();
iNoodles.cook();
iNoodles.box();
IPizzaProduct pizza = ldFactory.pizzaProduct();
pizza.material();
pizza.bake();
pizza.cut();
pizza.bake();
LanzhouFactory lanzhouFactory = new LanzhouFactory();
IPizzaProduct iPizzaProduct = lanzhouFactory.pizzaProduct();
iPizzaProduct.material();
iPizzaProduct.bake();
iPizzaProduct.cut();
iPizzaProduct.box();
IProductFactory factory = new LanzhouFactory();
INoodles noodles = factory.noddlesProduct();
noodles.material();
noodles.cook();
noodles.box();
}
运行截图
抽象工厂的优点
- 不关心创建细节: 用户只需要关心产品所对应的工厂,不需要关心它内部是如何创建
- 符合开闭原则: 加入新的产品,只需要增加新的工厂类就可以,符合开闭原则,提高了可扩展性
- 可以对产品族进行约束 因为有一个抽象的工厂类,其中可以对需要的产品族进行一个总体的约束
- 减少了具体工厂类的个数 因为现在只需要创建一个工厂,它可以利用方法创建一整个产品族
抽象工厂的不足
- 扩展产品族很困难: 因为现在是产品族约束是在抽象工厂接口里去定义的,所以如果需要增加一种新的产品种类,则之前所有实现这个工厂的具体工厂类都需要增加实现,所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。
- 增加难度:
增加了系统的抽象性和理解难度
(抽象工厂不仅抽象了产品类,同时还抽象了工厂类,增加了系统的抽象性和理解难度)。
设计模式的使用 , 要根据实际的业务场景 , 模型综合平衡考量 , 不能过分遵守设计原则 和 设计模式