说明:本文介绍设计模式中,创建型设计模式的抽象工厂设计模式;
工厂模式的问题
在【设计模式-2.2】创建型——简单工厂和工厂模式这篇博文中,介绍过飞机大战游戏里,使用简单工厂和工厂模式来创建坦克、飞机、Boss对象。
如果对象的类型过多,我们就需要创建更多的工厂类,并且如果我们需要对对象进行分类,如按照等级分类,坦克、飞机属于低等敌人,Boss属于高等敌人;按照战斗场景分类,坦克属于陆地,飞机属于天空,Boss可在陆地或者天空。
这就需要我们对现有的工厂类进一步抽取,抽象。
抽象工厂模式
在《秒懂设计模式》这本书中,提供了一种使用场景。如下:
作者假设某公司需要开发一款星际战争的游戏,游戏中兵种可分为人类与外星怪兽2个族,其中每个族又可分为1级、2级和3级,不同等级的兵种,攻击力、防御力和生命值不同;
(兵种接口)
/**
* 兵种抽象类
*/
public abstract class Unit {
/**
* 攻击力
*/
protected int attack;
/**
* 防御力
*/
protected int defence;
/**
* 生命值
*/
protected int health;
/**
* 横坐标
*/
protected int x;
/**
* 纵坐标
*/
protected int y;
public Unit(int attack, int defence, int health, int x, int y) {
this.attack = attack;
this.defence = defence;
this.health = health;
this.x = x;
this.y = y;
}
/**
* 出现
*/
public abstract void show();
/**
* 攻击
*/
public abstract void attack();
}
(低级兵种)
/**
* 低级兵种
*/
public abstract class LowClassUnit extends Unit{
/**
* 低级兵种
* @param x
* @param y
*/
public LowClassUnit(int x, int y) {
super(5, 2, 35, x, y);
}
}
(中级兵种)
/**
* 中级兵种
*/
public abstract class MidClassUnit extends Unit{
/**
* 中级兵种
* @param x
* @param y
*/
public MidClassUnit(int x, int y) {
super(10, 8, 80, x, y);
}
}
(高级兵种)
/**
* 高级兵种
*/
public abstract class HighClassUnit extends Unit{
/**
* 高级兵种
* @param x
* @param y
*/
public HighClassUnit(int x, int y) {
super(25, 30, 300, x, y);
}
}
(人族,低级兵种,海军陆战队)
/**
* 海军陆战队
*/
public class Marine extends LowClassUnit {
public Marine(int x, int y) {
super(x, y);
}
@Override
public void show() {
System.out.println("海军陆战队出现了,坐标为:(" + x + "," + y + ")");
}
@Override
public void attack() {
System.out.println("海军陆战队攻击,攻击力为:" + attack);
}
}
(人族,中级兵种,变形坦克)
/**
* 变形坦克
*/
public class Tank extends MidClassUnit{
/**
* 中级兵种
*
* @param x
* @param y
*/
public Tank(int x, int y) {
super(x, y);
}
@Override
public void show() {
System.out.println("变形坦克出现了,坐标为:(" + x + "," + y + ")");
}
@Override
public void attack() {
System.out.println("变形坦克攻击,攻击力为:" + attack);
}
}
(人族,高级兵种,巨型战舰)
/**
* 巨型战舰
*/
public class Battleship extends HighClassUnit{
/**
* 高级兵种
*
* @param x
* @param y
*/
public Battleship(int x, int y) {
super(x, y);
}
@Override
public void show() {
System.out.println("巨型战舰出现了,坐标为:(" + x + "," + y + ")");
}
@Override
public void attack() {
System.out.println("巨型战舰攻击,攻击力为:" + attack);
}
}
(怪兽族,低级兵种,螳螂)
/**
* 螳螂
*/
public class Roach extends LowClassUnit{
/**
* 低级兵种
*
* @param x
* @param y
*/
public Roach(int x, int y) {
super(x, y);
}
@Override
public void show() {
System.out.println("螳螂出现了,坐标为:(" + x + "," + y + ")");
}
@Override
public void attack() {
System.out.println("螳螂攻击,攻击力为:" + attack);
}
}
(怪兽组,中级兵种,毒液)
/**
* 毒液
*/
public class Poison extends MidClassUnit {
/**
* 中级兵种
*
* @param x
* @param y
*/
public Poison(int x, int y) {
super(x, y);
}
@Override
public void show() {
System.out.println("毒液出现了,坐标为:(" + x + "," + y + ")");
}
@Override
public void attack() {
System.out.println("毒液攻击,攻击力为:" + attack);
}
}
(怪兽组,高级兵种,猛犸)
/**
* 猛犸
*/
public class Mammoth extends HighClassUnit {
/**
* 高级兵种
*
* @param x
* @param y
*/
public Mammoth(int x, int y) {
super(x, y);
}
@Override
public void show() {
System.out.println("猛犸出现了,坐标为:(" + x + "," + y + ")");
}
@Override
public void attack() {
System.out.println("猛犸攻击,攻击力为:" + attack);
}
}
如果使用工厂模式来设计,那么需要创建6个工厂类,且这些工厂类互相没有联系,因此我们考虑使用抽象工厂模式,如下:
(抽象兵种工厂)
/**
* 抽象兵种工厂
*/
public interface AbstractFactory {
/**
* 创建低级兵种
* @return
*/
LowClassUnit createLowClassUnit();
/**
* 创建中级兵种
* @return
*/
MidClassUnit createMidClassUnit();
/**
* 创建高级兵种
* @return
*/
HighClassUnit createHighClassUnit();
}
(人类兵种工厂)
/**
* 人类兵种工厂
*/
public class HumanFactory implements AbstractFactory {
/**
* 横坐标
*/
private int x;
/**
* 纵坐标
*/
private int y;
public HumanFactory(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public LowClassUnit createLowClassUnit() {
LowClassUnit unit = new Marine(x, y);
System.out.println("制造海军陆战队员成功。");
return unit;
}
@Override
public MidClassUnit createMidClassUnit() {
MidClassUnit unit = new Tank(x, y);
System.out.println("制造变形坦克成功。");
return unit;
}
@Override
public HighClassUnit createHighClassUnit() {
HighClassUnit unit = new Battleship(x, y);
System.out.println("制造巨型战舰成功。");
return unit;
}
}
(外星怪兽兵种工厂)
/**
* 外星人兵种工厂
*/
public class AlienFactory implements AbstractFactory {
/**
* 横坐标
*/
private int x;
/**
* 纵坐标
*/
private int y;
public AlienFactory(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public LowClassUnit createLowClassUnit() {
LowClassUnit unit = new Roach(x, y);
System.out.println("制造蟑螂成功。");
return unit;
}
@Override
public MidClassUnit createMidClassUnit() {
MidClassUnit unit = new Poison(x, y);
System.out.println("制造毒液成功。");
return unit;
}
@Override
public HighClassUnit createHighClassUnit() {
HighClassUnit unit = new Mammoth(x, y);
System.out.println("制造猛犸象成功。");
return unit;
}
}
(客户端,演示人类兵种、怪兽兵种的创建)
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
System.out.println("......人类兵种工厂开始制造兵种......");
// 创建人类兵种工厂
AbstractFactory humanFactory = new HumanFactory(10, 10);
// 创建低级兵种
LowClassUnit humanLowClassUnit = humanFactory.createLowClassUnit();
// 创建中级兵种
MidClassUnit humanMidClassUnit = humanFactory.createMidClassUnit();
// 创建高级兵种
HighClassUnit humanHighClassUnit = humanFactory.createHighClassUnit();
// 低级兵种展示和攻击
humanLowClassUnit.show();
humanLowClassUnit.attack();
// 中级兵种展示和攻击
humanMidClassUnit.show();
humanMidClassUnit.attack();
// 高级兵种展示和攻击
humanHighClassUnit.show();
humanHighClassUnit.attack();
System.out.println("==========================================================");
System.out.println("......外星人兵种工厂开始制造兵种......");
// 创建外星人兵种工厂
AbstractFactory alienFactory = new AlienFactory(200, 200);
// 创建低级兵种
LowClassUnit alienLowClassUnit = alienFactory.createLowClassUnit();
// 创建中级兵种
MidClassUnit alienMidClassUnit = alienFactory.createMidClassUnit();
// 创建高级兵种
HighClassUnit alienHighClassUnit = alienFactory.createHighClassUnit();
// 低级兵种展示和攻击
alienLowClassUnit.show();
alienLowClassUnit.attack();
// 中级兵种展示和攻击
alienMidClassUnit.show();
alienMidClassUnit.attack();
// 高级兵种展示和攻击
alienHighClassUnit.show();
alienHighClassUnit.attack();
}
}
以上是抽象工厂模式创建对象的过程。抽象工厂模式是对工厂模式的一种提炼,当我们需要对系统中的对象进行分类区别时,应当考虑使用抽象工厂模式。
总结
本文参考《设计模式的艺术》、《秒懂设计模式》两书,代码来自《秒懂设计模式》,略有不同。