一、认识工厂模式
工厂模式定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂中,实现了创建者与调用者的分离!
工厂模式分类:简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂模式:将被创建的对象称为"产品",把创建产品的对象称为"工厂",若是产品不多,可通过使用一个工厂类即可完成,若是出现新的产品,需要去修改原有的方法,这违法了开闭原则。由于在简单工厂中创建对象的方法是static,所以又被称为静态工厂模式。该模式并不算在GoF23种设计模式之中。
应用场景:Spring中的BeanFactory。
工厂方法模式:解决了简单工厂模式违反开闭原则,在工厂方法模式中每一个产品都对应着一个工厂类,满足了开闭原则,就是需要付出更多的代价,若是产品特别多那么整体代码量会巨大。
应用场景:Spring与Mybatis的结合(FactoryBean接口)。
抽象工厂模式:围绕一个超级工厂来创建其他工厂,该超级工厂又称为其他工厂的工厂。
二、引出工厂模式
我们通常去创建一个对象的实例需要通过自己去手动new来创建实例,这种方式又称为无工厂模式,对于一些较复杂且需要多项配置时就比较头疼了,需要一个个填入到构造器中,造成不必要的麻烦!
下面代码就通过手动new的方式来获取实例:
interface Car { void name(); } //宝马 class BMW implements Car{ @Override public void name() { System.out.println("宝马"); } } //保时捷 class Porsche implements Car{ @Override public void name() { System.out.println("保时捷"); } } //消费者 public class Customer { public static void main(String[] args) { //通过手动new的方式来获取产品实例 Car bmw = new BMW(); Car porsche = new Porsche(); bmw.name(); porsche.name(); } }
在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替!
三、工厂模式实现
3.1、简单工厂模式
简单工厂模式:由于工厂的方法是static所以也叫做静态工厂模式。简单工厂模式有一个具体的工厂类,可以生成多个不同的产品,属于创建型设计模式。(但该模式并不在GoF23种设计模式中)
好处:
相对于无工厂模式,我们不再通过new来获取自己想要创建的实例,而是通过一个工厂类方法,只需要传入指定的参数就能够获取到我们想要的对象实例。
使用工厂方法时无需只要知道执行的类名,只需要知道能够创建实例的参数即可。
缺点:
一旦新增产品,我们就需要回到原有的工厂类创建实例方法中进行修改,否则无法扩展其他产品,这违反开闭原则(扩展功能,不要修改原来的方法)。
简单工厂模式工厂类单一,负责所有产品的创建,职责过重一旦出现异常整个系统都会受到影响,若是产品量过多,工厂类创建实例方法会非常臃肿。违法了单一职责原则。
应用场景:
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
简单工厂模式实现:
interface Car { void name(); } //宝马 class BMW implements Car{ @Override public void name() { System.out.println("宝马"); } } //保时捷 class Porsche implements Car{ @Override public void name() { System.out.println("保时捷"); } } public class CarFactory { //传入指定名称来获取具体产品实例 public static Car getCar(String name){ if("宝马".equals(name)){ return new BMW(); }else if("保时捷".equals(name)){ return new Porsche(); } return null; } } public class Main { public static void main(String[] args){ //通过工厂类来创建指定产品实例 Car bmw = CarFactory.getCar("宝马"); Car porsche = CarFactory.getCar("保时捷"); bmw.name(); porsche.name(); } }
添加了一个汽车工厂类CarFactory,其中添加一个创建产品方法getCar()根据传入参数来创建实例。
其中工厂创建方法通过if..else来判断创建也可以使用switch.case.进行创建。
说明:在简单工厂模式中,若是增加了其他产品则需要回到原来的方法中进行修改操作,这就违背了开闭原则,之后通过工厂方法模式则能够遵守该规则。不过有一说一,对于这种简单工厂模式在实际应用中会大量使用。
3.2、工厂方法模式
工厂方法模式:是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则,但是需要付出一定代价(对于产品很多并且零件很多情况下,造成创建工厂类过多情况)。
优点:
用户只需要知道具体工厂的名称即可得到所需要的产品,无需知道产品创建的过程。
更具有灵活性,当新增产品时,我们只需要创建一个相对应的工厂类,满足开闭原则。
典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
若是产品类过多,那么也就意味着创建对应数量的产品工厂,增加了复杂度。
增加了系统的抽象性和理解程度。
工厂方法模式实现:
在工厂方法模式中,我们添加一个工厂接口,一个产品对应一个工厂类,该工厂类实现该接口,顾客则通过指定产品的工厂类方法来获取产品实例,可见下图:
通过使用一个接口来规范工厂的获取实例方法:
interface Car { void name(); } //宝马 class BMW implements Car{ @Override public void name() { System.out.println("宝马"); } } //保时捷 class Porsche implements Car{ @Override public void name() { System.out.println("保时捷"); } } //新增一个工厂接口 interface Factory{ Car getCar(); } public class BMWFactory implements CarFactory{ @Override public Car getCar() { return new BMW(); } } public class PorscheFactory implements CarFactory{ @Override public Car getCar() { return new Porsche(); } } public class Main { public static void main(String[] args){ //通过对应产品的工厂类来获取实例 Car bmw = new BMWFactory().getCar(); Car porsche = new PorscheFactory().getCar(); bmw.name(); porsche.name(); } }
看一下多个接口及类的UML图:
我们能够看到结构变得更加清晰了,想要哪个汽车类型即可从对应类型的工厂中拿到,但是随着产品的增多,工厂类也会增多,增加了复杂度。
总结
简单工厂模式(静态工厂模式):其并不属于GoF23种设计模式的范畴中,并在某种程度上并不符合设计原则,但实际使用最多。
工厂方法模式:符合开闭原则,当添加新的产品时不需要更改原有的方法代码,直接通过增加新的工厂类实现扩展。
这两种模式都是针对于某个产品!