工厂模式

--什么是工厂模式?
--使用工厂模式的应用场景? 为啥用工厂模式,而不是需要的时候直接new Instance()?
--有哪几种工厂模式?优缺点?
--用简单工厂改进抽象工厂
--用反射改进抽象工厂

背景

假如你要制造一辆宝马BMW320,里面有A级别,B级别等的发动机,在初始化发动机A的时候,你第一想法应该就是

 EngineA engineA = new EngineA();  

但是A发动机在初始化的时候,还要对它的属性如价格和级别等进行初始化,那你这时候就会加上

engineA.setPrice(xxx);
engineA.setLevel(xxx);

也许还会有一些更复杂的初始化条件,这样就会在调用的方法里面加入一大堆和该方法不想关注到的细节,而且这些初始化工作一旦改变了,就需要在整个项目里面用到的地方都改个遍,维护起来就很艰难。这时候就需要用到工厂模式了。

定义

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。

应用场景

  • 创建实例时所做的初始化工作不是像赋值这样简单的事,
  • 可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了

三种工厂模式

1.简单工厂模式

直接上代码吧~
Engine.java

//面向接口编程
public interface Engine {

}

EngineA.java

public class EngineA implements Engine {
    public EngineA() {
        System.out.println("制造-->EngineA");
    }
}

EngineB.java

public class  EngineB implements Engine{
    public EngineB() {
        System.out.println("制造-->EngineB");
    }
}

BMW320Factory.java

public class BMW320Factory {

    public static Engine createEngine(String type){
        Engine engine = null;
        switch(type){
            case "A":
                engine = new EngineA();
                break;
            case "B":
                engine = new EngineB();
                break;
        }
        return engine;
    }
}

BMW320Test.java

public class BMW320Test {

    public static void main(String[] args) {
        BMW320Factory.createEngine("A");
        BMW320Factory.createEngine("B");
    }
}

看我们的测试类,很明显,只需要告诉工厂你要生成一个A级别的发动机,而不用知道工厂是怎样生成这个A发动机的,这里实现了调用和生成实例的解耦。
但是这时候又新来了一个C级别的发动机,你就要新新增一个EngineC,然后还需要在工厂类加上一个case,这种做法就违背了 “开放-封闭原则”。于是,工厂方法模式登场了~~

2.工厂方法模式

工厂方法模式是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
为了好分辨两种模式,新建一个包出来,保留上面Engine, EngineA, EngineB的java文件。新建以下类:
EngineFactory.java

public interface EngineFactory {
    Engine createEngine();
}

EngineAFactory.java

public class EngineAFactory implements EngineFactory {
    @Override
    public Engine createEngine() {
        return new EngineA();
    }
}

EngineBFactory.java

public class EngineBFactory implements EngineFactory {
    @Override
    public Engine createEngine() {
        return new EngineB();
    }
}

BMW320Test.java

public class BMW320Test {

    public static void main(String[] args) {
        EngineFactory engineFactory = new EngineAFactory();
        engineFactory.createEngine();

        EngineFactory engineFactory1 = new EngineBFactory();
        engineFactory1.createEngine();
    }
}

工厂方法模式分别为A,B级别的发动机创建了工厂,将简单工厂方法中的判断放在了客户端选择,每当新增一个其他级别的发动机,就不会修改到原来的类了。
细心的你一定会发现,这个模式一下子多了好几个类,而且BMW320上不止有发动机,还有空调,轮胎等,每多一个零件,就会要多新建实体和工厂。此时,抽象工厂模式该登场了~~

4.抽象工厂模式

抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。 该模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
再新建一个包,保留Engine, EngineA, EngineB的java文件。 新建空调的相关类。
Aircondition.java

public interface Aircondition {
}

AirconditionA.java

public class AirconditionA implements Aircondition {
    public AirconditionA(){
        System.out.println("制造-->AirconditionA");
    }
}

AirconditionB.java

public class AirconditionB implements Aircondition {
    public AirconditionB() {
        System.out.println("制造-->AirconditionB");
    }
}

抽象出一个汽车的工厂,里面可以生成发动机,也可以生成空调,轮胎等等。
AbstractFactory.java

public interface AbstractFactory {
    //制造发动机
    Engine createEngine();
    //制造空调
    Aircondition createAircondition();
}

组装成一辆BMW320
FactoryBMW320.java

public class FactoryBMW320 implements AbstractFactory {
    @Override
    public Engine createEngine() {
        return new EngineA();
    }

    @Override
    public Aircondition createAircondition() {
        return new AirconditionA();
    }
}

如果想组装成别的车辆也很方便,如BMW523用了A级发动机,和B型号的空调。
FactoryBMW523.java

class FactoryBMW523 implements AbstractFactory{

    @Override
    public Engine createEngine() {
        return new EngineA();
    }

    @Override
    public Aircondition createAircondition() {
        return new AirconditionB();
    }
}

AbstractfactoryTest.java

public class AbstractfactoryTest {

    public static void main(String[] args) {

        //抽象工厂
        FactoryBMW320 factoryBMW320 = new FactoryBMW320();
        factoryBMW320.createEngine();
        factoryBMW320.createAircondition();
        FactoryBMW523 factoryBMW523 = new FactoryBMW523();
        factoryBMW523.createEngine();
        factoryBMW523.createAircondition();
    }
}

到这里,抽象工厂模式就完成了。但你认真看下,BMW523和BMW320两个类的重复性这么高,能不能再抽象一点呢?下面再讲讲抽象工厂的优化。

优化:反射+抽象工厂方法

在简单工厂模式中,我们用到了switch或者if。有用到switch和if的地方,我们都可以考虑利用反射技术来去除,以解除分支带来的耦合。

这其实将会引申一个概念:依赖注入(DI),或者称为控制反转,将传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理,什么意思?就是直观上代码里看不到new 对象,这个操作交给了外部容器,这样将会大大降低程序的耦合性。比如:Spring框架的IoC容器。
新建一个包,保留模式3中的Engine, EngineA, EngineB, Aircondition, AirconditionA, AirconditionB的java文件。新建:
ImproveAbstractFactory.java

public interface ImproveAbstractFactory {
    //制造发动机
    public abstract <T extends Engine> T createEngine(Class<T> tClass);
    //制造空调
    public abstract <T extends Aircondition> T createAircondition(Class<T> tClass);
}

ImproveSpecificFactory.java

public class ImproveSpecificFactory implements ImproveAbstractFactory {
    @Override
    public  <T extends Engine> T createEngine(Class<T> tClass) {
        Engine engine = null;
        try{
            engine = (Engine) Class.forName(tClass.getName()).newInstance();
        }catch(Exception e){
            e.printStackTrace();
        }
        return (T) engine;
    }

    @Override
    public <T extends Aircondition> T createAircondition(Class<T> tClass) {
        Aircondition aircondition = null;
        try{
            aircondition = (Aircondition) Class.forName(tClass.getName()).newInstance();
        }catch(Exception e){
            e.printStackTrace();
        }
        return (T) aircondition;
    }
}

AbstractfactoryTest.java

public class AbstractfactoryTest {

    public static void main(String[] args) {

        //使用了反射 + 抽象工厂优化
        ImproveAbstractFactory improveAbstractFactory = new ImproveSpecificFactory();
        improveAbstractFactory.createEngine(EngineA.class);
        improveAbstractFactory.createAircondition(AirconditionA.class);

        improveAbstractFactory.createEngine(EngineB.class);
        improveAbstractFactory.createAircondition(AirconditionB.class);

    }
}

如果再进阶一下,是可以利用配置文件 + 反射来优化一些实例化操作的,在此先不讨论了。

参考:
http://c.biancheng.net/view/1351.html
https://www.cnblogs.com/yulinfeng/p/5847733.html
https://blog.csdn.net/qq_35642036/article/details/79663378#commentBox

posted @ 2019-11-27 11:05  cilieyes  阅读(150)  评论(0编辑  收藏  举报