创建篇-抽象工厂模式

Posted zhixuChen333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建篇-抽象工厂模式相关的知识,希望对你有一定的参考价值。

文章目录


前言

抽象工厂模式(Abstract Factory)是对工厂的抽象化,而不只是制造方法。我们知道,为了满足不同用户对产品的多样化需求,工厂不会只局限于生产一类产品,但是系统如果按工厂方法那样为每种产品都增加一个新工厂又会造成工厂泛滥。所以,为了调和这种矛盾,抽象工厂模式提供了另一种思路,将各种产品分门别类,基于此来规划各种工厂的制造接口,最终确立产品制造的顶级规范,使其与具体产品彻底脱钩。抽象工厂是建立在制造复杂产品体系需求基础之上的一种设计模式,在某种意义上,我们可以将抽象工厂模式理解为工厂方法模式的高度集群化升级版。


提示:以下是本篇文章正文内容,下面案例可供参考

一、品牌与系列

我们都知道,在工厂方法模式中每个实际的工厂只定义了一个工厂方法。而随着经济发展,人们对产品的需求不断升级,并逐渐走向个性化、多元化,制造业也随之发展壮大起来,各类工厂遍地开花,能够制造的产品种类也丰富了起来,随之而来的弊端就是工厂泛滥。

针对这种情况,我们就需要进行产业规划与整合,对现有工厂进行重构。例如,我们可以基于产品品牌与系列进行生产线规划,按品牌划分A工厂与B工厂。具体以汽车工厂举例,A品牌汽车有轿车、越野车、跑车3个系列的产品,同样地,B品牌汽车也包括以上3个系列的产品,如此便形成了两个产品族,分别由A工厂和B工厂负责生产,每个工厂都有3条生产线,分别生产这3个系列的汽车。基于这2个品牌汽车工厂的系列生产线,如果今后产生新的C品牌汽车、D品牌汽车等,都可以沿用此种规划好的生产模式,这便是抽象工厂模式的基础数据模型。

二、产品规划

1. 游戏建模

无论哪种工厂模式,都一定是基于特定的产品特性发展而来的,所以我们首先得从产品建模切入。假设某公司要开发一款星际战争游戏,战争设定在太阳系文明与异星系文明之间展开,游戏兵种就可以分为人类与外星怪兽2个族。

游戏战争场面相当激烈,人类拥有各种军工高科技装备,而外星怪兽则靠血肉之躯与人类战斗,所以这两族的兵种必然有着巨大的差异,这就意味着各兵种首先应该按族划分。此外,从另一个角度来看,它们又有相同之处,2个族的兵种都可以被简单归纳为初级(1级)、中级(2级)、高级(3级)3个等级,如同之前对汽车品牌系列的规划一样,各族兵种也应当按等级划分,最终我们可以得到一个对所有兵种分类归纳的表格。

1级2级3级
人类族海军陆战队变形坦克巨型战舰
怪兽族蟑螂毒液猛犸

2.兵种抽象类

任何兵种都具有攻击力、防御力、生命力、坐标方位等属性。除此之外,定义了展示show()(绘制到图上)与攻击attack()这两个抽象方法交由子类实现。

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();

接下来我们将兵种按等级分类,假设同一等级的攻击力、防御力等属性值是相同的,所以初级、中级、高级兵种会分别对应3个等级的兵种类。

//初级兵种类
public abstract class LowClassUnit extends Unit 

    public LowClassUnit(int x, int y) 
        super(5, 2, 35, x, y);
    


//中级兵种类
public abstract class MidClassUnit extends Unit 

    public MidClassUnit(int x, int y) 
        super(10, 8, 80, x, y);
    


//高级兵种类
public abstract class HighClassUnit extends Unit 

    public HighClassUnit(int x, int y) 
        super(25, 35, 300, x, y);
    


3.具体的兵种

各等级兵种类都继承自兵种抽象类Unit,它们对应的攻击力、防御力及生命力也各不相同,等级越高,其属性值也越高(当然制造成本也会更高,本例我们不考虑价格属性)。接下来我们来定义具体的兵种类,首先是人类兵种的海军陆战队员、变形坦克和巨型战舰,分别对应初级、中级、高级兵种。

//海军陆战队
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("士兵用机关枪射击,攻击力:" + super.attack);
    


//变形坦克类
public class Tank extends MidClassUnit 
    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("坦克用炮轰击,攻击力:" + super.attack);
    


//巨型战舰类
public class Battleship extends HighClassUnit 
    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("战舰用激光炮打击,攻击力:" + super.attack);
    


同样,外星怪兽族对应的初级、中级、高级兵种分别为蟑螂、毒液、猛犸。

//蟑螂
public class Roach extends LowClassUnit 
    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("蟑螂兵用钩子挠,攻击力:" + super.attack);
    


//毒液
public class Poison extends MidClassUnit 
    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("毒液兵用毒液喷射,攻击力:" + super.attack);
    


//猛犸
public class Mammoth extends HighClassUnit 
    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("猛犸巨兽用獠牙顶,攻击力:" + super.attack);
    

说明:

  1. 至此,所有兵种类已定义完毕,代码不是难点,重点集中在对兵种的划分上,横向划分族,纵向划分等级(系列),利用类的抽象与继承描绘出所有的游戏角色以及它们之间的关系,同时避免了不少重复代码。

三、生产线规划

既然产品类的数据模型构建完成,相应的产品生产线也应该建立起来,接下来我们就可以定义这些产品的制造工厂了。我们一共定义了6个兵种产品,那么每个产品都需要对应一个工厂类吗?答案是否定的。本着人类靠科技、怪兽靠繁育的游戏理念,人类兵工厂自然是高度工业化的,而怪兽的生产一定靠的是母巢繁殖,所以应该将工厂分为2个族,并且每个族工厂都应该拥有3个等级兵种的制造方法。如此规划不但合理,而且避免了工厂类泛滥的问题。

1.工厂标准制定

首先我们来制定这3个工业制造标准,也就是定义抽象工厂接口。

public interface AbstractFactory 
    LowClassUnit createLowClass(); //初级兵种制造标准

    MidClassUnit createMidClass(); //中级兵种制造标准

    HighClassUnit createHighClass(); //高级兵种制造标准


2. 具体工厂类

抽象兵工厂接口定义了3个等级兵种的制造标准,这意味着子类工厂必须具备初级、中级、高级兵种的生产能力(类似一个品牌的不同系列生产线)。理解了这一点后,我们就可以定义人类兵工厂与外星母巢的工厂类实现了。

//人类兵工厂
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 createLowClass() 
        LowClassUnit unit = new Marine(x, y);
        System.out.println("制造海军陆战队成功。");
        return unit;
    

    @Override
    public MidClassUnit createMidClass() 
        MidClassUnit unit = new Tank(x, y);
        System.out.println("制造变形坦克成功。");
        return unit;
    

    @Override
    public HighClassUnit createHighClass() 
        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 createLowClass() 
        LowClassUnit unit = new Roach(x, y);
        System.out.println("制造蟑螂兵成功。");
        return unit;
    

    @Override
    public MidClassUnit createMidClass() 
        MidClassUnit unit = new Poison(x, y);
        System.out.println("制造毒液兵成功。");
        return unit;
    

    @Override
    public HighClassUnit createHighClass() 
        HighClassUnit unit = new Mammoth(x, y);
        System.out.println("制造猛犸巨兽成功。");
        return unit;
    

3.客户端类

所有兵种与工厂准备完毕,我们可以用客户端开始模拟游戏了。

public class Client 
    public static void main(String[] args) 
        System.out.println("游戏开始......");
        System.out.println("双方挖矿攒钱......");

        //第一位玩家选择人类族
        System.out.println("工人建造人类族工厂......");
        AbstractFactory factory = new HumanFactory(10,10);

        Unit marine = factory.createLowClass();
        marine.show();

        Unit tank = factory.createMidClass();
        tank.show();

        Unit ship = factory.createHighClass();
        ship.show();

        //第二位玩家选择了外星怪兽族
        System.out.println("工蜂建造外星怪兽族工厂......");
        factory = new AlienFactory(200 , 200);

        Unit roach = factory.createLowClass();
        roach.show();

        Unit poison = factory.createMidClass();
        poison.show();

        Unit mammoth = factory.createHighClass();
        mammoth.show();

        System.out.println("两大族开始混战......");
        marine.attack();
        roach.attack();
        poison.attack();
        tank.attack();
        mammoth.attack();
        ship.attack();
    

输出结果:
游戏开始
绘制飞机于上层图层,出现坐标63,0
飞机向玩家发起攻击......
绘制坦克于下层图层,出现坐标45,0
坦克向玩家发起攻击......

说明:

  1. 此时,如果玩家需要一个新族加入,我们可以在此模式之上去实现一个新的族工厂并实现3个等级的制造方法,工厂一经替换即可产出各系列产品兵种,且无须改动现有代码,良好的可扩展性一览无遗,这就是一套拥有完备生产模式的标准化工业系统所带来的好处。

四、分而治之

至此,抽象工厂制造模式已经布局完成,各工厂可以随时大规模投入生产活动了。当然,我们还可以进一步,再加一个“制造工厂的工厂”来决定具体让哪个工厂投入生产活动。此时客户端就无须关心工厂的实例化过程了,直接使用产品就可以了,至于产品属于哪个族也已经无关紧要,这也是抽象工厂可以被视为“工厂的工厂”的原因。

public class FactoryProducer 
    public static AbstractFactory getFactory(String type, int x, int y) 
        AbstractFactory abstractFactory = null;
        switch (type)
            case "human":
                abstractFactory = new HumanFactory(x,y);
                break;
            case "alien":
                abstractFactory = new AlienFactory(x,y);
                break;
        
        return abstractFactory;
    

总结

提示:这里对文章进行总结:

  1. 与工厂方法模式不同,抽象工厂模式能够应对更加复杂的产品族系,它更类似于一种对“工业制造标准”的制定与推行,各工厂实现都遵循此标准来进行生产活动,以工厂类划分产品族,以制造方法划分产品系列,达到无限扩展产品的目的。
  2. 抽象工厂方法模式的各角色定义如下。
  • AbstractProduct1、AbstractProduct2(抽象产品1、抽象产品2):产品系列的抽象类,对应本章例程中的初级、中级、高级兵种抽象类。
  • ProductA1、ProductB1、ProductA2、ProductB2(产品A1、产品B1、产品A2、产品B2):继承自抽象产品的产品实体类,其中ProductA1与ProductB1代表A族产品与B族产品的同一产品系列,类似于本章例程中人类族与外星怪兽族的初级兵种,之后的产品实体类以此类推。
  • ConcreteFactoryA、ConcreteFactoryB(工厂A实现、工厂B实现):继承自抽象工厂的各族工厂,需实现抽象工厂所定义的产品系列制造方法,可以扩展多个工厂实现。对应本章例程中的人类兵工厂与外星母巢。
  • Client(客户端):产品的使用者,只关心制造出的产品系列,具体是哪个产品族由工厂决定。
  1. 产品虽然繁多,但总有品牌、系列之分。基于此抽象工厂模式以品牌与系列进行全局规划,将看似杂乱无章的产品规划至不同的族系,再通过抽象工厂管理起来,分而治之,合纵连横。需要注意的是,抽象工厂模式一定是基于产品的族系划分来布局的,其产品系列一定是相对固定的,故以抽象工厂来确立工业制造标准(各产品系列生产接口)。而产品族则可以相对灵活多变,如此一来,我们就可以方便地扩展与替换族工厂,以达到灵活产出各类产品族系的目的。

以上是关于创建篇-抽象工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

一天一个设计模式:抽象方法模式

#yyds干货盘点#-设计模式分享-抽象工厂模式

设计模式抽象工厂模式 ( 简介 | 适用场景 | 优缺点 | 产品等级结构和产品族 | 代码示例 )

Java设计模式——抽象工厂模式

抽象工厂模式

抽象工厂模式