创建型设计模式_02--抽象工厂模式

前言

本来昨天已经把这一篇发出来了,但是突然发现好像自己的理解有些问题,这就尴尬了,于是又去看了一下网上的众多帖子,再次梳理总结一下我对抽象工厂模式的理解。

本篇主要讲的是我个人对抽象工厂模式的理解以及java实现的demo


原理

首先抽象工厂模式(Abstract Factory Pattern)主要是用于解决创建复杂对象的问题,和工厂模式的 区别在于,工厂模式所创建的对象一般都实现了某一个接口,也就是说他们都具有某一类特定的功能;而抽象工厂模式还解决了接口选择的问题,他所创建的对象可以分为几大类(等级),每个类别的对象分别实现一个接口,并且每个类别下的具体类是一一对应的。而系统要使用时只会使用其中的一个类别的对象,下面举个例子说明:

假设我们有一个生产服装的超级工厂,它的下面有三个子工厂,分别用于生产商务装,休闲装和运动装。我们知道不管是哪个类别工厂生产的套装,都是由一样的东西构成的:上衣、裤子、鞋子。当我们需要一套衣服时,我们首先去超级工厂看看自己想要哪一类的套装,假设我们想要运动装,那么超级工厂就会让我们去运动装生产工厂,去“生产”一套运动装–运动服,运动裤,运动鞋。需要其他类型套装的也是如此,注意,每种工厂只会生产对应的一套套装,比如我们去商务装工厂是生产不了运动装的。

总结起来就是,抽象工厂模式就是围绕一个超级工厂来创建一个具体的工厂,系统需要使用的就是某一个具体工厂的一套产品。我们把每一个工厂所能生产的所有产品叫做一个等级,比如上面服装有运动型,休闲型,商务型。把每个具体工厂下相同种类的产品叫做一个产品族,比如上面的上衣是一个产品族,裤子是一个产品族,鞋子是一个产品族。抽象工厂模式的最大特点就是增加一个等级比较简单,新建一座具体工厂就行,比如我要新增一个礼服等级,只需要新建一个专门生产礼服的工厂,然后再去超级工厂等级一下;但是增加一个产品族就很困难了,需要改变所有的工厂才能实现,比如我要增加一个帽子产品族,则需要在每个具体工厂里都增加做帽子的功能,当已经有的产品族较多时,这是非常困难的。

例如QQ的主题/皮肤有白天模式,黑夜模式,蓝色主题,红色主题等等,每一个主题就是一个等级,每种主题下都会有亮度、大小、颜色、图标等一系列具体的设置,系统每次只会从主题库(超级工厂)里选择一套主题(一个具体工厂)来配置界面,从选择的主题中提取图标、字体、亮度、颜色这一套配置,就相当于用一个具体的工厂创建了一套想要的产品等级。

可以看出,抽象工厂模式可以把创建出来的对象限制在某一类别之下,这种模式特别适用于管理具有不同等级、不同产品族的产品,控制他们的创造方式。


java实现

好了,啰嗦了这么多,下面用一个具体的例子说明,并且用代码实现一下。

故事是这样的,世界上有一种见不得光的职业叫杀手,他们会下面几件事:

  1. 搞到一把趁手的枪外加它的配套的子弹– getWeapon();
  2. 把子弹填到枪里–assembel();
  3. 寻找刺杀目标–findTarget();
  4. 射击–shoot();

于是,我们用Killer这个抽象类来表示:

public abstract class Killer {

    //搞到武器
    public abstract void getWeapon();

    //闭着眼睛都能组装武器
    public void assemble(){
        System.out.println("killer:weapon assembled !");
    }
    //每次都顺利找到目标
    public void findTarget(){
        System.out.println("killer:target found !");
    }
    //假设杀手命中率100%
    public void shoot(){
        System.out.println("killer:target killed !");
    }
}

我们假设每个杀手的武器都是枪,都需要子弹:

//枪的父类
public class Gun{...}
//子弹的父类
public class Bullet{...}

有的杀手比较喜欢AK47的枪,自然要配上AK47的子弹:

AKWeapon.java

//接口AKWeapon 所有AK生产的东西都实现了这个接口
public interface AKWeapon {
    void logInfo();
}
AKGun.java

//AK所生产的枪AK47
public class AkGun extends Gun implements AKWeapon {

    @Override
    public void logInfo() {
        // TODO Auto-generated method stub
        System.out.println("ak_gun got from factory.");
    }

}

AKBullet.java

//AK生产的专门配AK枪的子弹
public class AKBullet extends Bullet implements AKWeapon {

    @Override
    public void logInfo() {
        // TODO Auto-generated method stub
        System.out.println("ak_bullets got from factory");
    }

}

萝卜白菜各有所爱,有的杀手就喜欢沙漠之鹰的枪,当然只能配沙漠之鹰的子弹:

SmzyWeapon.java

//所有沙漠之鹰工厂生产的枪和子弹都实现这个接口,这是一种沙漠之鹰的标记
public interface SmzyWeapon {
    void logInfo();
}
SmzyGun.java

//沙漠之鹰生产的枪
public class SmzyGun extends Gun implements SmzyWeapon {

    @Override
    public void logInfo() {
        // TODO Auto-generated method stub
        System.out.println("smzy_gun got from factory.");
    }

}
SmzyBullet.java

//沙漠之鹰的配套子弹
public class SmzyBullet extends Bullet implements SmzyWeapon {

    @Override
    public void logInfo() {
        // TODO Auto-generated method stub
        System.out.println("smzy_bullet got from factory.");
    }

}

那么问题来了,假设我是一个刚入行,还没有武器的杀手小白,今天接到了第一单生意,要我去刺杀某个国家的总统。于是,我得先去弄清楚在哪里可以搞到武器(一直听说沙漠之鹰很厉害,所以我决定去搞一套AK47的武器)。

经过杀手界的前辈指点,所有的杀手(不管用什么武器)都会去离自己最近一个超级武器工厂来获取武器,我住的地方附近就有一个超级工厂,不过规模比较小,只有两个子工厂,一个专门生产AK的武器,包括AK47和它的子弹,另一个专门生产沙漠之鹰和对应的子弹。虽说两个子工厂生产的武器等级不一样,但是抽象一下,都是武器工厂嘛:

WeaponFactory.java

//抽象的武器工厂,可能会生产AK或者沙漠之鹰以及配套的子弹
public abstract class WeaponFactory {
    public abstract AKWeapon createAKWeapon(String aKType);
    public abstract SmzyWeapon createSmzyWeapon(String smzyType);
}

处于好奇,我首先去专门生产沙漠之鹰的具体工厂看了一下:

SmzyFactory.java

//专门生产沙漠之鹰的工厂
public class SmzyFactory extends WeaponFactory {
    //果然只能生产沙漠之鹰
    @Override
    public AKWeapon createAKWeapon(String aKType) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public SmzyWeapon createSmzyWeapon(String smzyType) {
        // TODO Auto-generated method stub
        String type = smzyType.toLowerCase();
        if(type.equals("gun")){
            System.out.println("smzy_factory: create sumzy_gun;");
            return new SmzyGun();
        }else if(type.equals("bullet")){
            System.out.println("smzy_factory: create sumzy_bullet;");
            return new SmzyBullet();
        }
        return null;
    }
}

接着,我又去了专门生产AK的工厂:

AKFactory.java

//专门生产AK的工厂
public class AKFactory extends WeaponFactory {

    @Override
    public AKWeapon createAKWeapon(String aKType) {
        // TODO Auto-generated method stub
        String type = aKType.toLowerCase();
        if(type.equals("gun")){
            System.out.println("ak_factory: create ak_gun;");
            return new AkGun();
        }else if(type.equals("bullet")){
            System.out.println("ak_factory: create ak_bullet;");
            return new AKBullet();
        }
        return null;
    }
    //果然只生产AK
    @Override
    public SmzyWeapon createSmzyWeapon(String smzyType) {
        // TODO Auto-generated method stub
        return null;
    }
}

逛完之后,我再次回到了超级工厂:

public class SuperFactory {
    public static WeaponFactory createWeaponFactory(String fType){
        String type = fType.toLowerCase();
        if(type.equals("ak")){
            System.out.println("super_factory: create ak_factory;");
            return new AKFactory();
        }else if(type.equals("smzy")){
            System.out.println("super_factory: create smzy_factory;");
            return new SmzyFactory();
        }
        return null;
    }
}

那里的人问我:“尊敬的客人,请问你要使用的是什么武器?”
我说:“AK吧,我比较用的来”.
–”好的,请直接去那边那个叫做ak的武器工厂”

于是,搞到了武器的我正式成为了一个用AK的杀手:

public class AKKIller extends Killer {

    @Override
    public void getWeapon() {
        // TODO Auto-generated method stub
        //杀手告诉超级工厂我只用AK的武器,工厂让我去对应的AK工厂
        WeaponFactory factory = SuperFactory.createWeaponFactory("ak");
        //拿到枪和子弹(都是AK武器)
        AKWeapon gun = factory.createAKWeapon("gun");
        AKWeapon bullet = factory.createAKWeapon("bullet");
        System.out.println("akKiller:weapon got !");
    }

}

有了枪和子弹,还等什么?干活去了

public class Demo {
    public static void main(String args[]){
        AKKIller akKiller = new AKKIller();
        akKiller.getWeapon();
        akKiller.assemble();
        akKiller.findTarget();
        akKiller.shoot();
    }
}

任务记录:

super_factory: create ak_factory;//去ak工厂吧
ak_factory: create ak_gun;//拿到AK47
ak_factory: create ak_bullet;//拿到AK的子弹
akKiller:weapon got !//一手交钱,一手交货
killer:weapon assembled !//装弹
killer:target found !//找目标、瞄准
killer:target killed !//射击!任务完成

… …

时代在改变,连超级工厂也要扩建了,首先它计划能够让杀手们在它那能买到经典的左轮手枪和左轮子弹。那么,需要怎么办呢,首先当然是新建一个专门生产左轮产品的左轮工厂,接着给生产出来的枪和子弹实现左轮特有的标记,左轮接口(ZuoLunWeapon.java),修改一下抽象工厂的可能生产出的武器等级(加一个左轮类别)就可以了。

随着时间的推移,超级工厂下面也有了十几个子工厂,可以生产出包括沙漠之鹰和AK47在内的十几种枪和子弹。然而,新的问题又来了,杀手们希望所有的枪和子弹能再配一个弹夹,以携带更多的子弹,也就是说,超级工厂得增加弹夹这个产品族(包括沙漠之鹰弹夹和AK47弹夹以及后来扩建之后的工厂应该有的左轮弹夹等等十几种弹夹),这下就麻烦了,所有的子工厂都得停止生产,先引进各自所需的弹夹生产线,才能继续生产。

看来,增加等级类别比较简单,要增加产品族就难了。

以上代码只是我对抽象工厂模式理解的一个比较粗浅的实现,没有考虑null对象的问题。也不知道理解的对不对,欢迎指正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值