今天聊一聊大家最耳熟能详的设计模式,『工厂模式』。实际上这个设计模式有三个变种,分别是『简单工厂模式』、『工厂方法模式』以及『抽象工厂模式』,可能大部人所熟知的是前两种,抽象工厂模式有一定的场景限制,很少出现在大家的视野中,不过今天我们一并谈一谈。

简单工厂模式

简单工厂说白了就是一个超级工厂,他可以生产各种各样的产品,产品之间无关联,比如:

public interface SimpleFactory {

    //生产一个冰箱
    Refrigerator createRefiger();

    //生产一个空调
    AirConditioning createAirConditioning();

    //生产一个 TV
    TV createTV();
}

一般也会有一个默认的实现:

public class DefaultSimpleFactory implements SimpleFactory{

    @Override
    public Refrigerator createRefiger() {
        return new Refrigerator();
    }

    @Override
    public AirConditioning createAirConditioning() {
        return new AirConditioning();
    }

    @Override
    public TV createTV() {
        return new TV();
    }
}

这就是一个简单工厂模式,非常的简单,还没有很强的抽象性。

Spring 的 BeanFactory 其实就是一个简单工厂模式,他定义了一个 BeanFactory 工厂,然后会有 DefaultListableBeanFactory 去实现这个工厂声明的所有能力。

工厂方法模式

其实理论上来说,可以把简单工厂模式理解为工厂方法模式的一种特例,将他的那个超级大工厂拆分成多个工厂就是工厂方法模式了。

同样有一个抽象接口表述一个工厂:

public interface MethodFactory {

    //生产一个冰箱
    Refrigerator createRefiger();

    //生产一个空调
    AirConditioning createAirConditioning();

    //生产一个 TV
    TV createTV();
}

简单工厂是用一个 DefaultFactory 完成了工厂所有的能力要求。但是现在我们的厂家变多了,有格力冰箱、海尔冰箱、海信冰箱等等,他们生产的冰箱或空调都不一样,如果用简单工厂的话,就需要做区分,增加更多的方法,生产格力冰箱的,生产海尔冰箱的,非常的丑陋。

工厂方法模式,需要区分不同的工厂,这里我们创建格力工厂、海尔工厂和海信工厂。

public class GeliFactory implements MethodFactory {

    @Override
    public Refrigerator createRefiger() {
        return new GeliRefrigerator();
    }

    @Override
    public AirConditioning createAirConditioning() {
        return new GeliAirConditioning();
    }

    @Override
    public TV createTV() {
        return new GeliTV();
    }
}

格力工厂返回的是格力的空调、格力的冰箱以及格力的电视机,海尔和海信也都会返回他们自己品牌的产品,这里就不贴他们的代码了,类似。

这样,我们的工厂方法对外提供了生产产品的能力,具体产生何种类型的产品,将由具体的工厂决定。这就是工厂方法模式,相信大部分人应该都不陌生。

Logpack 中就有一个典型的工厂方法,工厂抽象类 ILoggerFactory:

public interface ILoggerFactory {
    Logger getLogger(String var1);
}

他有两个具体的工厂实现这个 getLogger 方法,

public class NOPLoggerFactory implements ILoggerFactory {
    public NOPLoggerFactory() {
    }

    public Logger getLogger(String name) {
        return NOPLogger.NOP_LOGGER;
    }
}
public class SubstituteLoggerFactory
            implements ILoggerFactory {
    //省略
    public synchronized Logger getLogger(String name) {
        SubstituteLogger logger = (SubstituteLogger)this.loggers.get(name);
        if (logger == null) {
            logger = new SubstituteLogger(name, this.eventQueue, this.postInitialization);
            this.loggers.put(name, logger);
        }

        return logger;
    }//省略。。。。。
}

抽象工厂模式

抽象工厂模式可能不如前两者常见,但是确是为了补充前两者的,有特定的场景。

想象这么一种情况,你使用了工厂方法模式,你的工厂提供的能力非常多,可以生产冰箱、电视、空调、洗衣机、电脑以及桌子等等,这样你就会产生很多的工厂。

抽象工厂的作用就是在一定前提下,帮你分类这些工厂,比如按品牌分类,或者按照价格等级分类,这样会大大缩减系统中的工厂数量。

这个前提就是你的这些工厂需要在两个维度上具备共性:

工厂模式和抽象工厂的区别是什么?-LMLPHP

专业术语就是『产品等级』和『产品族』两个概念,说人话就是,这些工厂需要至少具有两个共性,比如都可以按照类型区分成三类,电视机、冰箱和空调,也可以按照品牌区分成海尔、海信和 TCL。

这样他们就具备抽象工厂的前提条件,你可以按照产品族合并工厂,正如我上面使用到的例子一样,工厂对外提供生产电视、冰箱和空调三种能力,而系统按品牌存在三个工厂,所以从准确来说,我在工厂方法中使用的例子其实也是加强版的抽象工厂模式。

代码例子就不举例了,抽象工厂其实就是帮助减少系统的工厂数量的,但前提条件就是这些工厂要具备两个及以上的共性

希望你被面试官问道工厂方法和抽象工厂的区别的时候,能想起这一句话。


关注公众不迷路,一个爱分享的程序员。

公众号回复「1024」加作者微信一起探讨学习!

公众号回复「面试题」送你一份面试题以及作者的作答答案

每篇文章用到的所有案例代码素材都会上传我个人 github

https://github.com/SingleYam/overview_java

欢迎来踩!

工厂模式和抽象工厂的区别是什么?-LMLPHP

04-19 03:17