抽象工厂模式-原理到实战应用(基于Dart语言)

面向对象之设计模式
抽象工厂模式-原理到实战应用(Dart版)

- 文章信息 -
Author: 李俊才 (jcLee95)
Visit me at: https://jclee95.blog.csdn.net
Email: [email protected].
Shenzhen China
Address of this article:https://blog.csdn.net/qq_28550263/article/details/131731937

【介绍】:本文介绍抽象工厂模式原理及其应用。

提示:建议阅读本文前先阅读并掌握 工厂模式https://blog.csdn.net/qq_28550263/article/details/131729619

上一节:《 工厂模式-原理到实战应用(Dart版) | 下一节:《 构建器模式-原理到实战应用(Dart版)


1. 引例

在上一篇博文中,我们为“工厂模式”给出了一个创建“游戏角色”的例子。接下来仍然假设我们有一个游戏开发中的角色系统,不同的是现在我们不仅需要创建不同种类的人物角色,还要创建角色对应的装备。其中角色的类别包括 Warrior(战士)、Mage(法师)、Rogue(盗贼);装备类别包括 Weapons(武器)、Gloves(手套)、Chestplate(胸甲)、Boots(靴子)、Ring(截止)、Relic(法宝)。

现在我们如果直接分别对人物角色和装备,则需要先创建所有的角色类和所有的装备类,然后对角色和装备进行组合,使用通过 new 关键字创建具体的角色和具体的装备,这样的代码显然将很难维护。

那么上一篇博文介绍的工厂模式可以完成这次的人物吗?

Creator
+createProduct()
ConcreteCreatorA
+createProduct()
ConcreteCreatorB
+createProduct()
Product
+operation()
ConcreteProductA
+operation()
ConcreteProductB
+operation()
Client
图 1: 工厂模式结构图

从 图1 中我们可以看出,工厂模式中有两个抽象类或接口分别表示 抽象工厂(Creator)和抽象产品(Product),实际上由某个 具体工厂(如ConcreteCreatorA)来生产某个像对应的具体产品(如ConcreteProductA),整个过程仅仅涉及同一类产品的生产。比如在上一个例子中,不论哪个具体的角色类都属于同一个大类 Character,每一个具体的角色类由一个对于的角色工厂进行创建。

很显然,由于这个例子中具体产品分属于两个大类,工厂模式失效了。

2. 什么是抽象工厂模式

2.1 抽象工厂模式原理

抽象工厂模式是一种创建型设计模式,它提供了一种方法来创建一组相关或相互依赖的对象,而无需指定其具体类。该模式通过引入抽象工厂和抽象产品类,将对象的创建和使用分离开来,从而实现了更高层次的解耦。与工厂模式相同的是,在抽象工厂模式中,也有以下四个核心组件:

组件 描述
抽象工厂(AbstractFactory) 定义了用于创建一组相关产品的接口。它通常包含多个工厂方法,每个方法用于创建一个具体产品。
具体工厂(ConcreteFactory) 实现了抽象工厂接口,负责创建具体产品的实例。每个具体工厂对应于一个产品族,即一组相关的产品。
抽象产品(AbstractProduct) 定义了产品的接口,描述了产品的共同属性和方法。
具体产品(ConcreteProduct) 实现了抽象产品接口,具体产品与具体工厂相对应,代表了某个具体的产品。

抽象工厂模式各个组件之间的结构关系可由如 图2 UML所表示。

实现或继承
实现或继承
创建
创建
创建
创建
实现或继承
实现或继承
实现或继承
实现或继承
AbstractFactory
+FactoryMethod()
ConcreteFactory1
+createProductA()
+createProductB()
+FactoryMethod()
ConcreteFactory2
+createProductA()
+createProductB()
+FactoryMethod()
AbstractProductA
+usefulFunctionA()
ConcreteProductA1
+usefulFunctionA()
ConcreteProductA2
+usefulFunctionA()
AbstractProductB
+usefulFunctionB()
+anotherUsefulFunctionB()
ConcreteProductB1
+usefulFunctionB()
+anotherUsefulFunctionB()
ConcreteProductB2
+usefulFunctionB()
+anotherUsefulFunctionB()
图 2: 抽象工厂模式结构图

2.2 与工厂模式的不同

抽象工厂模式和工厂模式是两种常见的设计模式,它们有一些相似之处,但也有一些区别。

  1. 目的和使用范围不同:

    • 工厂模式(Factory Pattern)旨在通过封装对象的创建过程来实现对象的实例化,以便在运行时根据客户端需求动态创建对象。
    • 抽象工厂模式(Abstract Factory Pattern)则提供一种方式来创建一系列相关的对象,而无需按照具体的类进行实例化。
  2. 关注点不同:

    • 工厂模式关注于创建对象,它提供了一个独立的工厂类来负责创建产品。
    • 抽象工厂模式关注于创建一系列相关的产品,它使用抽象工厂接口来定义这些产品,并由具体工厂类来实现创建过程。
  3. 扩展性不同:

    • 工厂模式相对较简单,通过添加新的具体工厂类和产品类来扩展已有代码。
    • 抽象工厂模式更加灵活,通过添加新的抽象产品类和具体工厂类来扩展已有代码。

总之,工厂模式适用于需要根据不同的实例化需求创建对象的情况,而抽象工厂模式适用于需要创建一系列相关产品的情况。根据具体的需求和设计目标,选择适合的设计模式可以提高代码的可维护性和扩展性。

3. 实战:通过抽象工厂模式建模并给出代码

3.1 人物角色

现在我们回过头来思考本文开篇提出的例子。在我们开发一款游戏时,不仅需要创建不同种类的人物角色,还要创建角色对应的装备。其中角色的类别包括 Warrior(战士)、Mage(法师)、Rogue(盗贼);装备类别包括 Weapons(武器)、Gloves(手套)、Chestplate(胸甲)、Boots(靴子)、Ring(截止)、Relic(法宝)。

因此整体上我们要创建的时带装备的角色,角色和装备都应该各自依据某种规则被创建。因此不妨将角色和装备视作 具体产品,它们由抽象的人物角色和抽象的装备所泛化。

其中有关于人物角色的结构如图3所示:

Character
+blood: double
+mana: double
+grade: int
+display()
Warrior
+blood: double
+mana: double
+grade: int
+display()
Mage
+blood: double
+mana: double
+grade: int
+display()
Rogue
+blood: double
+mana: double
+grade: int
+display()
图 3: 任务角色结构图

可以依据 UML 完成这部分对应的代码:

// 抽象产品:角色
abstract class Character {
    
    
  late double blood; // 血量
  late double mana; // 法力值
  late int grade; // 等级

  void display(); // 显示角色信息
}

// 具体产品:战士
class Warrior implements Character {
    
    
  late double blood;
  late double mana;
  late int grade;

  Warrior([double blood = 200, double mana = 0, int grade = 1]) {
    
    
    this.blood = blood;
    this.mana = mana;
    this.grade = grade;
  }

  
  void display() {
    
    
    print("战士:血量=$blood, 法力值=$mana, 等级=$grade");
  }
}

// 具体产品:法师
class Mage implements Character {
    
    
  late double blood;
  late double mana;
  late int grade;

  Mage([double blood = 100, double mana = 100, int grade = 1]) {
    
    
    this.blood = blood;
    this.mana = mana;
    this.grade = grade;
  }

  
  void display() {
    
    
    print("法师:血量=$blood, 法力值=$mana, 等级=$grade");
  }
}

3.2 角色装备

其中有关于角色装备的结构如图4所示:

Equipment
+wear: double
+display()
Weapons
+wear: double
+display()
Chestplate
+wear: double
+display()
Boots
+wear: double
+display()
Relic
+wear: double
+display()
Gloves
+wear: double
+display()
Ring
+wear: double
+display()
图 4: 装备结构图

可以依据 UML 完成这部分对应的代码:

// 抽象产品:装备
abstract class Equipment {
    
    
  double wear = 100.0; // 耐久度

  void display(); // 显示装备信息
}

// 具体产品:武器
class Weapons implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("武器:耐久度=$wear");
  }
}

// 具体产品:胸甲
class Chestplate implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("胸甲:耐久度=$wear");
  }
}

// 具体产品:鞋子
class Boots implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("鞋子:耐久度=$wear");
  }
}

// 具体产品:法器
class Relic implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("法器:耐久度=$wear");
  }
}

// 具体产品:手套
class Gloves implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("手套:耐久度=$wear");
  }
}

// 具体产品:指环
class Ring implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("指环:耐久度=$wear");
  }
}

3.3 战士工厂

现在我们需要考虑,有一些工厂,不仅仅可以生产人物角色,同时生产对应的装备。考虑到不同角色的装备不同,这实际上就是说一个工厂内需要同时生产人物角色及其对应的装备。例如有一个战士工厂,它不仅仅需要生产战士,还需要生产战士的武器、胸甲、鞋子这些装备。依据此可以绘制战士工厂的 UML 图,如图5所示:

WarriorFactory
+createCharacter()
+createEquipments()
Warrior
+blood: double
+mana: double
+grade: int
+display()
Weapons
+wear: double
+display()
Chestplate
+wear: double
+display()
Boots
+wear: double
+display()
图 5: 战士工厂结构图

可以依据 UML 相应地写出这部分代码:

// 具体产品:武器
class Weapons implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("武器:耐久度=$wear");
  }
}

// 具体产品:胸甲
class Chestplate implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("胸甲:耐久度=$wear");
  }
}

// 具体产品:鞋子
class Boots implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("鞋子:耐久度=$wear");
  }
}

// 具体工厂:战士工厂
class WarriorFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Warrior();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 战士自带武器、鞋子、胸甲装备
    return List<Equipment>.from([Boots(), Weapons(), Chestplate()]);
  }
}

3.4 法师工厂

同理,我们可以绘制法师工厂的结构图,如图6所示:

MageFactory
+createCharacter()
+createEquipments()
Mage
+blood: double
+mana: double
+grade: int
+display()
Boots
+wear: double
+display()
Relic
+wear: double
+display()
Ring
+wear: double
+display()
图 6: 法师工厂结构图

对应于 UML 的代码实现为:

// 具体工厂:法师工厂
class MageFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Mage();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 法师自带鞋子、法器、指环装备
    return List<Equipment>.from([Boots(), Relic(), Ring()]);
  }
}

// 具体产品:鞋子
class Boots implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("鞋子:耐久度=$wear");
  }
}

// 具体产品:法器
class Relic implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("法器:耐久度=$wear");
  }
}

// 具体产品:指环
class Ring implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("指环:耐久度=$wear");
  }
}

3.5 盗贼工厂

同理,我们可以绘制盗贼工厂的结构图,如图6所示:

RogueFactory
+createCharacter()
+createEquipments()
Rogue
+blood: double
+mana: double
+grade: int
+display()
Gloves
+wear: double
+display()
Boots
+wear: double
+display()
图 7: 盗贼工厂结构图

对应于 UML 的代码实现为:

// 具体工厂:盗贼工厂
class RogueFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Rogue();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 盗贼自带鞋子和手套装备
    return List<Equipment>.from([Boots(), Gloves()]);
  }
}

// 具体产品:手套
class Gloves implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("手套:耐久度=$wear");
  }
}

// 具体产品:鞋子
class Boots implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("鞋子:耐久度=$wear");
  }
}

3.6 游戏工厂

从最顶层来看,游戏工厂提供统一的接口,是一个抽象工厂。而用户混合生产各种具体产的的工厂,如 “战士工厂”、“法师工厂”、“盗贼工厂” 都是基础或者实现了该工厂工厂。这部分的 结构如图8所示:

GameFactory
+createCharacter()
+createEquipments()
WarriorFactory
+createCharacter()
+createEquipments()
MageFactory
+createCharacter()
+createEquipments()
RogueFactory
+createCharacter()
+createEquipments()
图 8:游戏工厂结构图

对应的代码实现为:

// 抽象工厂
abstract class GameFactory {
    
    
  Character createCharacter(); // 创建角色
  List<Equipment> createEquipments(); // 创建装备
}

// 具体工厂:战士工厂
class WarriorFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Warrior();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 战士自带武器、鞋子、胸甲装备
    return List<Equipment>.from([Boots(), Weapons(), Chestplate()]);
  }
}

// 具体工厂:法师工厂
class MageFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Mage();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 法师自带鞋子、法器、指环装备
    return List<Equipment>.from([Boots(), Relic(), Ring()]);
  }
}

// 具体工厂:盗贼工厂
class RogueFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Rogue();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 盗贼自带鞋子和手套装备
    return List<Equipment>.from([Boots(), Gloves()]);
  }
}

3.7 整体实现

整体上,可以绘制出完整的 UML 类图,如图9所示:

Character
+blood: double
+mana: double
+grade: int
+display()
Warrior
+blood: double
+mana: double
+grade: int
+display()
Mage
+blood: double
+mana: double
+grade: int
+display()
Rogue
+blood: double
+mana: double
+grade: int
+display()
Equipment
+wear: double
+display()
Weapons
+wear: double
+display()
Chestplate
+wear: double
+display()
Boots
+wear: double
+display()
Relic
+wear: double
+display()
Gloves
+wear: double
+display()
Ring
+wear: double
+display()
GameFactory
+createCharacter()
+createEquipments()
WarriorFactory
+createCharacter()
+createEquipments()
MageFactory
+createCharacter()
+createEquipments()
RogueFactory
+createCharacter()
+createEquipments()
图 9: 整体结构图

通过 UML类图 编写代码,对应的完整代码为:

// 抽象产品:角色
abstract class Character {
    
    
  late double blood; // 血量
  late double mana; // 法力值
  late int grade; // 等级

  void display(); // 显示角色信息
}

// 具体产品:战士
class Warrior implements Character {
    
    
  late double blood;
  late double mana;
  late int grade;

  Warrior([double blood = 200, double mana = 0, int grade = 1]) {
    
    
    this.blood = blood;
    this.mana = mana;
    this.grade = grade;
  }

  
  void display() {
    
    
    print("战士:血量=$blood, 法力值=$mana, 等级=$grade");
  }
}

// 具体产品:法师
class Mage implements Character {
    
    
  late double blood;
  late double mana;
  late int grade;

  Mage([double blood = 100, double mana = 100, int grade = 1]) {
    
    
    this.blood = blood;
    this.mana = mana;
    this.grade = grade;
  }

  
  void display() {
    
    
    print("法师:血量=$blood, 法力值=$mana, 等级=$grade");
  }
}

// 具体产品:盗贼
class Rogue implements Character {
    
    
  late double blood;
  late double mana;
  late int grade;

  Rogue([double blood = 100, double mana = 0, int grade = 1]) {
    
    
    this.blood = blood;
    this.mana = mana;
    this.grade = grade;
  }

  
  void display() {
    
    
    print("盗贼:血量=$blood, 法力值=$mana, 等级=$grade");
  }
}

// 抽象产品:装备
abstract class Equipment {
    
    
  double wear = 100.0; // 耐久度

  void display(); // 显示装备信息
}

// 具体产品:武器
class Weapons implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("武器:耐久度=$wear");
  }
}

// 具体产品:胸甲
class Chestplate implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("胸甲:耐久度=$wear");
  }
}

// 具体产品:鞋子
class Boots implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("鞋子:耐久度=$wear");
  }
}

// 具体产品:法器
class Relic implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("法器:耐久度=$wear");
  }
}

// 具体产品:手套
class Gloves implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("手套:耐久度=$wear");
  }
}

// 具体产品:指环
class Ring implements Equipment {
    
    
  double wear = 100.0;

  
  void display() {
    
    
    print("指环:耐久度=$wear");
  }
}

// 抽象工厂
abstract class GameFactory {
    
    
  Character createCharacter(); // 创建角色
  List<Equipment> createEquipments(); // 创建装备
}

// 具体工厂:战士工厂
class WarriorFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Warrior();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 战士自带武器、鞋子、胸甲装备
    return List<Equipment>.from([Boots(), Weapons(), Chestplate()]);
  }
}

// 具体工厂:法师工厂
class MageFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Mage();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 法师自带鞋子、法器、指环装备
    return List<Equipment>.from([Boots(), Relic(), Ring()]);
  }
}

// 具体工厂:盗贼工厂
class RogueFactory implements GameFactory {
    
    
  
  Character createCharacter() {
    
    
    return Rogue();
  }

  
  List<Equipment> createEquipments() {
    
    
    // 盗贼自带鞋子和手套装备
    return List<Equipment>.from([Boots(), Gloves()]);
  }
}

我们可以在一个主函数中调用上面的代码进行简单地测试:

void main() {
    
    
  // 使用战士工厂创建战士角色和武器装备
  GameFactory warriorFactory = WarriorFactory();
  Character warrior = warriorFactory.createCharacter();
  List<Equipment> warriorEquipments = warriorFactory.createEquipments();

  // 使用法师工厂创建法师角色和法器装备
  GameFactory mageFactory = MageFactory();
  Character mage = mageFactory.createCharacter();
  List<Equipment> mageEquipments = mageFactory.createEquipments();

  // 使用盗贼工厂创建盗贼角色和手套装备
  GameFactory rogueFactory = RogueFactory();
  Character rogue = rogueFactory.createCharacter();
  List<Equipment> rogueEquipments = rogueFactory.createEquipments();
  print('-----------------------------');
  // 显示角色和装备信息
  warrior.display();
  warriorEquipments.forEach((element) {
    
    
    element.display();
  });
  print('-----------------------------');
  mage.display();
  mageEquipments.forEach((element) {
    
    
    element.display();
  });
  print('-----------------------------');
  rogue.display();
  rogueEquipments.forEach((element) {
    
    
    element.display();
  });
}

输出结果为:

-----------------------------
战士:血量=200.0, 法力值=0.0, 等级=1
鞋子:耐久度=100.0
武器:耐久度=100.0
胸甲:耐久度=100.0
-----------------------------
法师:血量=100.0, 法力值=100.0, 等级=1
鞋子:耐久度=100.0
法器:耐久度=100.0
指环:耐久度=100.0
-----------------------------
盗贼:血量=100.0, 法力值=0.0, 等级=1
鞋子:耐久度=100.0
手套:耐久度=100.0

可以看到,战士工厂、法师工厂、盗贼工厂,不仅仅可以生产自己需要的角色(依次对应战士、法师、盗贼),同时可以生产对应于自己角色的装备。如战士的装备为武器、胸甲、鞋子;法师的装备为法器、鞋子、指环;盗贼的装备为鞋子、手套。这就是我们所说的抽象工厂模式再实际开发的一个应用的例子。

猜你喜欢

转载自blog.csdn.net/qq_28550263/article/details/131731937