你觉得工厂模式很简单,多是由于你懂的只是冰山的一角

GitHub 3.2k Star 的Java工程师成神之路 ,不来了解一下吗?java

GitHub 3.2k Star 的Java工程师成神之路 ,真的不来了解一下吗?git

GitHub 3.2k Star 的Java工程师成神之路 ,真的肯定不来了解一下吗?github

不少人认为工厂模式很简单,只是有一个建造工厂,帮咱们进行对象构造而已。那么请尝试回答下如下问题:算法

一、工厂模式分为几类?
二、GOF 23种设计模式中,工厂方法模式和抽象工厂模式有什么区别?
三、不在GOF 23种设计模式中的简单工厂模式是什么?
四、简单工厂模式、工厂方法模式和抽象工厂模式各自解决什么问题?有什么不一样?数据库

若是以上四个问题,你均可以很好的回答的话,那么这篇文章就没有继续读下去的必要了,不然,建议你好好学习下本文。设计模式

三种工厂模式

工厂模式能够分为三类:ide

  • 1)简单工厂模式(Simple Factory)学习

  • 2)工厂方法模式(Factory Method)优化

  • 3)抽象工厂模式(Abstract Factory)this

这三种模式从上到下逐步抽象,而且更具通常性。

GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。

将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,二者归为一类。

这三种工厂模式在设计模式的分类中都属于建立型模式

建立型模式(Creational Pattern)对类的实例化过程进行了抽象,可以将软件模块中对象的建立和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只须要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。

建立型模式在建立什么(What),由谁建立(Who),什么时候建立(When)等方面都为软件设计者提供了尽量大的灵活性。

建立型模式隐藏了类的实例的建立细节,经过隐藏对象如何被建立和组合在一块儿达到使整个系统独立的目的。

工厂模式是建立型模式中比较重要的。工厂模式的主要功能就是帮助咱们实例化对象的。之因此名字中包含工厂模式四个字,是由于对象的实例化过程是经过工厂实现的,是用工厂代替new操做的。

这样作的好处是封装了对象的实例化细节,尤为是对于实例化较复杂或者对象的生命周期应该集中管理的状况。会给你系统带来更大的可扩展性和尽可能少的修改量。

接下来咱们分别介绍下这三种工厂模式。

简单工厂模式

简单工厂模式是属于建立型模式,又叫作静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定建立出哪种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,能够理解为是不一样工厂模式的一个特殊实现。

在介绍简单工厂模式以前,咱们尝试解决如下问题:

如今咱们要使用面向对象的形式定义计算器,为了实现各算法之间的解耦。主要的用到的类以下:

// 计算类的基类
public abstract class Operation {

    private double value1 = 0;
    private double value2 = 0;

    public double getValue1() {
        return value1;
    }
    public void setValue1(double value1) {
        this.value1 = value1;
    }
    public double getValue2() {
        return value2;
    }
    public void setValue2(double value2) {
        this.value2 = value2;
    }
    protected abstract double getResule();
}

//加法
public class OperationAdd extends Operation {
    @Override
    protected double getResule() {
        return getValue1() + getValue2();
    }
}
//减法
public class OperationSub extends Operation {
    @Override
    protected double getResule() {
        return getValue1() - getValue2();
    }
}
//乘法
public class OperationMul extends Operation {
    @Override
    protected double getResule() {
        return getValue1() * getValue2();
    }
}
//除法
public class OperationDiv extends Operation {
    @Override
    protected double getResule() {
        if (getValue2() != 0) {
            return getValue1() / getValue2();
        }
        throw new IllegalArgumentException("除数不能为零");
    }
}

当我想要执行加法运算时,可使用以下代码:

public class Main {
    public static void main(String[] args) {
        OperationAdd operationAdd = new OperationAdd();
        operationAdd.setValue1(10);
        operationAdd.setValue2(5);
System.out.println(operationAdd.getResule());
    }
}

当我须要执行减法运算时,我就要建立一个OperationSub类。也就是说,我想要使用不一样的运算的时候就要建立不一样的类,而且要明确知道该类的名字。

那么这种重复的建立类的工做其实能够放到一个统一的工厂类中。简单工厂模式有如下优势:

一、一个调用者想建立一个对象,只要知道其名称就能够了。

二、屏蔽产品的具体实现,调用者只关心产品的接口。

简单工厂模式实现方式

简单工厂模式其实和他的名字同样,很简单。先来看看它的组成:

Factory:这是本模式的核心,含有必定的商业逻辑和判断逻辑。在java中它每每由 一个具体类实现。(OperationFactory)

Product:它通常是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。(Operation)

ConcreteProduct:工厂类所建立的对象就是此角色的实例。在java中由一个具体类实现。 来用类图来清晰的表示下的它们之间的关系(OperationAdd\OperationSub等)

在原有类的基础上,定义工厂类:

//工厂类
public class OperationFactory {

    public static Operation createOperation(String operation) {
        Operation oper = null;
        switch (operation) {
            case "+":
                oper = new OperationAdd();
                break;
            case "-":
                oper = new OperationSub();
                break;
            case "*":
                oper = new OperationMul();
                break;

            case "/":
                oper = new OperationDiv();
                break;
            default:
                throw new UnsupportedOperationException("不支持该操做");
        }
        return oper;
    }
}

有了工厂类以后,可使用工厂建立对象:

Operation operationAdd = OperationFactory.createOperation("+");
operationAdd.setValue1(10);
operationAdd.setValue2(5);
System.out.println(operationAdd.getResule());

经过简单工厂模式,该计算器的使用者不须要关系实现加法逻辑的那个类的具体名字,他只要知道该类对应的参数"+"就能够了。

简单工厂模式存在的问题

当咱们须要增长一种计算时,例如开平方。这个时候咱们须要先定义一个类继承Operation类,其中实现平方的代码。除此以外咱们还要修改OperationFactory类的代码,增长一个case。这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。

咱们举的例子是最简单的状况。而在实际应用中,极可能产品是一个多层次的树状结构。 简单工厂可能就不太适用了。

简单工厂模式总结

工厂类是整个简单工厂模式的关键。包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该建立哪一个具体类的对象。经过使用工厂类,外界能够从直接建立具体产品对象的尴尬局面摆脱出来,仅仅须要负责“消费”对象就能够了。而没必要管这些对象究竟如何建立及如何组织的。明确了各自的职责和权利,有利于整个软件体系结构的优化。

可是因为工厂类集中了全部实例的建立逻辑,违反了高内聚责任分配原则,将所有建立逻辑集中到了一个工厂类中;它所能建立的类只能是事先考虑到的,若是须要添加新的类,则就须要改变工厂类了。

当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不一样条件建立不一样实例的需求.这种对条件的判断和对具体产品类型的判断交错在一块儿,很难避免模块功能的蔓延,对系统的维护和扩展很是不利;

这些缺点在工厂方法模式中获得了必定的解决。

工厂方法模式

工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类建立型模式。

工厂方法模式是一种实现了“工厂”概念的面向对象设计模式。就像其余建立型模式同样,它也是处理在不指定对象具体类型的状况下建立对象的问题。

工厂方法模式的实质是“定义一个建立对象的接口,但让实现这个接口的类来决定实例化哪一个类。工厂方法让类的实例化推迟到子类中进行。”

工厂方法模式用途

工厂方法模式和简单工厂模式虽然都是经过工厂来建立对象,他们之间最大的不一样是——工厂方法模式在设计上彻底彻底符合“开闭原则”。

在如下状况下可使用工厂方法模式:

一个类不知道它所须要的对象的类:在工厂方法模式中,客户端不须要知道具体产品类的类名,只须要知道所对应的工厂便可,具体的产品对象由具体工厂类建立;客户端须要知道建立具体产品的工厂类。

一个类经过其子类来指定建立哪一个对象:在工厂方法模式中,对于抽象工厂类只须要提供一个建立产品的接口,而由其子类来肯定具体要建立的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

将建立对象的任务委托给多个工厂子类中的某一个,客户端在使用时能够无须关心是哪个工厂子类建立产品子类,须要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

工厂方法模式实现方式

工厂方法模式包含以下角色:

Product:抽象产品(Operation

ConcreteProduct:具体产品(OperationAdd)

Factory:抽象工厂(IFactory)

ConcreteFactory:具体工厂(AddFactory)

这里还用计算器的例子。在保持OperationOperationAddOperationDivOperationSubOperationMul等几个方法不变的状况下,修改简单工厂模式中的工厂类(OperationFactory)。替代原有的那个"万能"的大工厂类,这里使用工厂方法来代替:

//工厂接口
public interface IFactory {
    Operation CreateOption();
}

//加法类工厂
public class AddFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationAdd();
    }
}

//除法类工厂
public class DivFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationDiv();
    }
}

//除法类工厂
public class MulFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationMul();
    }
}

//减法类工厂
public class SubFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationSub();
    }
}

这样,在客户端中想要执行加法运算时,须要如下方式:

public class Main {

    public static void main(String[] args) {
        IFactory factory = new AddFactory();
        Operation operationAdd =  factory.CreateOption();
        operationAdd.setValue1(10);
        operationAdd.setValue2(5);
        System.out.println(operationAdd.getResult());
    }
}

到这里,一个工厂方法模式就已经写好了。

从代码量上看,这种工厂方法模式比简单工厂方法模式更加复杂。针对不一样的操做(Operation)类都有对应的工厂。不少人会有如下疑问:

貌似工厂方法模式比简单工厂模式要复杂的多?

工厂方法模式和我本身建立对象没什么区别?为何要多搞出一些工厂来?

下面就针对以上两个问题来深刻理解一下工厂方法模式。

为何要使用工厂来建立对象?

封装对象的建立过程

在工厂方法模式中,工厂方法用来建立客户所须要的产品,同时还向客户隐藏了哪一种具体产品类将被实例化这一细节,用户只须要关心所需产品对应的工厂,无须关心建立细节,甚至无须知道具体产品类的类名。

基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它可以使工厂能够自主肯定建立何种产品对象,而如何建立这个对象的细节则彻底封装在具体工厂内部。工厂方法模式之因此又被称为多态工厂模式,是由于全部的具体工厂类都具备同一抽象父类。

为何每种对象要单独有一个工厂?

符合『开放-封闭原则』

主要目的是为了解耦。在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其余的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就能够了。这样,系统的可扩展性也就变得很是好,彻底符合“开闭原则。

以上就是工厂方法模式的优势。可是,工厂模式也有一些不尽如人意的地方:

在添加新产品时,须要编写新的具体产品类,并且还要提供与之对应的具体工厂类,系统中类的个数将成对增长,在必定程度上增长了系统的复杂度,有更多的类须要编译和运行,会给系统带来一些额外的开销。

因为考虑到系统的可扩展性,须要引入抽象层,在客户端代码中均使用抽象层进行定义,增长了系统的抽象性和理解难度,且在实现时可能须要用到DOM、反射等技术,增长了系统的实现难度。

工厂方法模式总结

工厂方法模式是简单工厂模式的进一步抽象和推广。

因为使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优势,并且克服了它的缺点。

在工厂方法模式中,核心的工厂类再也不负责全部产品的建立,而是将具体建立工做交给子类去作。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式能够容许系统在不修改工厂角色的状况下引进新产品。

工厂方法模式的主要优势是增长新的产品类时无须修改现有系统,并封装了产品对象的建立细节,系统具备良好的灵活性和可扩展性;其缺点在于增长新产品的同时须要增长新的工厂,致使系统类的个数成对增长,在必定程度上增长了系统的复杂性。

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern):提供一个建立一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象建立型模式。

抽象工厂模式提供了一种方式,能够将同一产品族的单独的工厂封装起来。在正常使用中,客户端程序须要建立抽象工厂的具体实现,而后使用抽象工厂做为接口来建立这一主题的具体对象。客户端程序不须要知道(或关心)它从这些内部的工厂方法中得到对象的具体类型,由于客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的通常使用分离开来。

产品族

来认识下什么是产品族: 位于不一样产品等级结构中,功能相关的产品组成的家族。以下面的例子,就有两个产品族:跑车族和商务车族。

抽象工厂模式用途

抽象工厂模式和工厂方法模式同样,都符合开放-封闭原则。可是不一样的是,工厂方法模式在增长一个具体产品的时候,都要增长对应的工厂。可是抽象工厂模式只有在新增一个类型的具体产品时才须要新增工厂。也就是说,工厂方法模式的一个工厂只能建立一个具体产品。而抽象工厂模式的一个工厂能够建立属于一类类型的多种具体产品。工厂建立产品的个数介于简单工厂模式和工厂方法模式之间。

在如下状况下可使用抽象工厂模式:

一个系统不该当依赖于产品类实例如何被建立、组合和表达的细节,这对于全部类型的工厂模式都是重要的。

系统中有多于一个的产品族,而每次只使用其中某一产品族。

属于同一个产品族的产品将在一块儿使用,这一约束必须在系统的设计中体现出来。

系统提供一个产品类的库,全部的产品以一样的接口出现,从而使客户端不依赖于具体实现。

抽象工厂模式实现方式

抽象工厂模式包含以下角色:

AbstractFactory(抽象工厂):用于声明生成抽象产品的方法

ConcreteFactory(具体工厂):实现了抽象工厂声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每个产品都位于某个产品等级结构中;

AbstractProduct(抽象产品):为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法;

Product(具体产品):定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。

本文的例子采用一个汽车代工厂造汽车的例子。假设咱们是一家汽车代工厂商,咱们负责给奔驰和特斯拉两家公司制造车子。咱们简单的把奔驰车理解为须要加油的车,特斯拉为须要充电的车。其中奔驰车中包含跑车和商务车两种,特斯拉一样也包含奔驰车和商务车。

以上场景,咱们就能够把跑车和商务车分别对待,对于跑车有单独的工厂建立,商务车也有单独的工厂。这样,之后不管是再帮任何其余厂商造车,只要是跑车或者商务车咱们都不须要再引入工厂。一样,若是咱们要增长一种其余类型的车,好比越野车,咱们也不须要对跑车或者商务车的任何东西作修改。

下面是抽象产品,奔驰车和特斯拉车:

public interface BenzCar {
    //加汽油
    public void gasUp();

}

public interface TeslaCar {
    //充电
    public void charge();
}

下面是具体产品,奔驰跑车、奔驰商务车、特斯拉跑车、特斯拉商务车:

public class BenzSportCar implements BenzCar {
    public void gasUp() {
        System.out.println("给个人奔驰跑车加最好的汽油");
    }
}

public class BenzBusinessCar implements BenzCar{
    public void gasUp() {
        System.out.println("给个人奔驰商务车加通常的汽油");
    }
}

public class TeslaSportCar implements TeslaCar {
    public void charge() {
        System.out.println("给我特斯拉跑车冲满电");
    }
}

public class TeslaBusinessCar implements TeslaCar {
    public void charge() {
        System.out.println("不用给我特斯拉商务车冲满电");
    }
}

下面是抽象工厂:

public interface CarFactory {

    public BenzCar getBenzCar();
    public TeslaCar getTeslaCar();
}

下面是具体工厂:

public class SportCarFactory implements CarFactory {
    public BenzCar getBenzCar() {
        return new BenzSportCar();
    }

    public TeslaCar getTeslaCar() {
        return new TeslaSportCar();
    }
}

public class BusinessCarFactory implements CarFactory {
    public BenzCar getBenzCar() {
        return new BenzBusinessCar();
    }

    public TeslaCar getTeslaCar() {
        return new TeslaBusinessCar();
    }
}

“开闭原则”的倾斜性

“开闭原则”要求系统对扩展开放,对修改封闭,经过扩展达到加强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能加强包括两方面:

增长产品族:对于增长新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增长的产品族,只须要对应增长一个新的具体工厂便可,对已有代码无须作任何修改。

增长新的产品等级结构:对于增长新的产品等级结构,须要修改全部的工厂角色,包括抽象工厂类,在全部的工厂类中都须要增长生产新产品的方法,不能很好地支持“开闭原则”。

抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增长新的产品,它为新产品族的增长提供方便,但不能为新的产品等级结构的增长提供这样的方便。

抽象工厂模式总结

抽象工厂模式提供一个建立一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象建立型模式。

抽象工厂模式是全部形式的工厂模式中最为抽象和最具通常性的一种形态。

抽象工厂模式的主要优势是隔离了具体类的生成,使得客户并不须要知道什么被建立,并且每次能够经过具体工厂类建立一个产品族中的多个对象,增长或者替换产品族比较方便,增长新的具体工厂和产品族很方便;主要缺点在于增长新的产品等级结构很复杂,须要修改抽象工厂和全部的具体工厂类,对“开闭原则”的支持呈现倾斜性。

三种工厂模式对比

简单工厂模式的优缺点

  • 优势:
    • 一、屏蔽产品的具体实现,调用者只关心产品的接口。
    • 二、实现简单
  • 缺点:
    • 一、增长产品,须要修改工厂类,不符合开放-封闭原则
    • 二、工厂类集中了全部实例的建立逻辑,违反了高内聚责任分配原则

工厂方法模式的优缺点

  • 优势:
    • 一、继承了简单工厂模式的优势
    • 二、符合开放-封闭原则
  • 缺点:
    • 一、增长产品,须要增长新的工厂类,致使系统类的个数成对增长,在必定程度上增长了系统的复杂性。

抽象工厂模式的优缺点

  • 优势:
    • 一、隔离了具体类的生成,使得客户并不须要知道什么被建立
    • 二、每次能够经过具体工厂类建立一个产品族中的多个对象,增长或者替换产品族比较方便,增长新的具体工厂和产品族很方便;
  • 缺点
    • 增长新的产品等级结构很复杂,须要修改抽象工厂和全部的具体工厂类,对“开闭原则”的支持呈现倾斜性。

简单工厂 : 用来生产同一等级结构中的任意产品。(对于增长新的产品,主要是新增产品,就要修改工厂类。符合单一职责原则。不符合开放-封闭原则)

工厂方法 :用来生产同一等级结构中的固定产品。(支持增长任意产品,新增产品时不须要更改已有的工厂,须要增长该产品对应的工厂。符合单一职责原则、符合开放-封闭原则。可是引入了复杂性)

抽象工厂 :用来生产不一样产品族的所有产品。(增长新产品时,须要修改工厂,增长产品族时,须要增长工厂。符合单一职责原则,部分符合开放-封闭原则,下降了复杂性)

最后,三种工厂模式各有优缺点,没有最好的,只有最合适的!

相关文章
相关标签/搜索