需求

暂且不提工厂模式, 我们先了解一个简单的需求, 然后通过这个需求的改进过程了解工厂模式。 需求如下 :

假设现在,我有一辆车Car,它有一个 go() 方法, 代码很简单,如下 :

1
2
3
4
5
public class Car {
    public void go(){
        System.out.println("Car run ~");
    }
}

我们同时有一辆新的交通工具飞机 Airplane, 同样也有一个 go() 方法, 代码如下 :

1
2
3
4
5
public class Airplane {
    public void go(){
        System.out.println("Airplane fly ~");
    }
}

这时,如果我们第一次坐🚗Car, 然后再坐✈️飞机,代码就得这样写:

1
2
3
4
5
6
    public static void main(String[] args) {
//        Car c = new Car();
//        c.go();
        Airplane a = new Airplane();
        a.go();
    }

在坐车时, new一个 🚗对象,🚗.go().

在坐飞机时,new 一个✈️对象, ✈️go().

这时候,如果我们又要坐火车🚄呢?

我们要做的就是,再添加一个 Train类,并实现 🚄的 go() 方法。 并在 main 函数中 new 一个🚄对象,🚄.go();

所以,每次添加一种交通工具,我们都需要添加类,并实现 go() 方法。 有没有更好的方法,可扩展性更好呢?

答案就是,为交通工具建一个父类。利用面向对象的多态,增加可扩展性。

  • 在Java中,我们可以使用 抽象父类 abstract class 解决
  • 也可以使用 interface接口解决,这里我们使用 interface解决
    • 新建一个 interface 接口 Moveable,其中添加一个方法 go()
    • 并且让我们所有的交通工具都实现 Moveable 接口的方法 go()
1
2
3
public interface Moveable {
    public void go();
}
1
2
3
4
5
6
public class Car implements Moveable{
    @Override
    public void go() {
        System.out.println("Car run ~");
    }
}
1
2
3
4
5
6
public class Airplane implements Moveable{
    @Override
    public void go() {
        System.out.println("Airplane run ~");
    }
}

这时,Main函数中的代码就可以这样写

1
2
3
4
5
6
public static void main(String[] args) {
    Moveable c = new Car();
    c.go();
    Moveable m = new Airplane();
    m.go();
}

以上是多态的简单运用。

我们又有新的需求? 定制生产过程, 也就是,在 new Car() 的前后,需要做一些事情。 如果按照上边方法做,就需要在main 函数中一通修改。如果更方便的定制生产过程? 引入了我们的主角,工厂模式

定义

什么是工厂呢?

  • 任何可以产生对象的方法或类,都可以称之为工厂
  • 单例也是一种工厂
  • 工厂主要有三种
    • 简单工厂
    • 工厂方法
    • 抽象工厂

一,简单工厂

接下来,我们通过,简单工厂模式,来解决 定制生产过程 的问题

  • 我们创建一个 VehicelFactory ,此类专门用来生产各种交通工具
  • 这样,我们就可以在 工厂类中,定制生产交通工具时业务逻辑所需要的过程
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class VehicelFactory {
    public static Car createCar(){
        // 这里可以处理业务逻辑所需要的定制过程
        return new Car();
    }
    
    public static Airplane createAirplane(){
        // 这里可以处理业务逻辑所需要的定制过程
        return new Airplane();
    }
}

我们main 函数处的代码就简单了

1
2
3
4
5
6
public static void main(String[] args) {
    Moveable c = VehicelFactory.createCar();
    c.go();
    Moveable m = VehicelFactory.createAirplane();
    m.go();
}
  • 以上就是简单工厂模式的一个应用
  • 有一些缺点
    • 扩展性并不好
      • 增加一种交通工具,就需要在 VehicelFactory中创建方法,和一大堆的业务逻辑
      • 随着业务逻辑变多,VehicelFactory 会变得越来越庞大,难以维护

如何解决,VehicelFactory 不好扩展的问题呢 ? 答案就是: 工厂方法

二,工厂方法

  • 工厂方法,也是使用工厂类创建交通工具
  • 不同之处在于,工厂方法中,我们为每个类,创建一个 Factory用于定制其生产过程。
    • 比如,我们为 Car创建一个 CarFactory 类生产 🚗
    • 为 Airplane创建一个 AirplaneFactory类 生产 ✈️
  • 很显然,工厂方法不会产生庞大的 VehicelFactory 工厂
  • 增加一种交通工具时,为新的交通工具创建对应的 Factory 即可

代码如下 :

1
2
3
4
5
6
public class AirplaneFactory{
    public static Moveable create(){
        // 这里可以处理业务逻辑所需要的定制过程
        return new Airplane();
    }
}
1
2
3
4
5
6
public class CarFactory {
    public static Moveable create(){
        // 这里可以处理业务逻辑所需要的定制过程
        return new Car();
    }
}
1
2
3
4
public static void main(String[] args) {
    Moveable c = CarFactory.create();
    c.go();
}
  • 这样我们就解决了,在交通工具类很多时扩展性的问题

现在, 我们又有新需求了。 如何定制一系列的产品呢?

比如一个现实世界的人,可以一辆车,可以拿武器AK47,可以吃面包

而一个魔法世界的人,可以 骑扫帚,可以拿武器魔法棒, 可以吃蘑菇

如何来定制这一类人对应的一系列产品呢 ? 答案就是,抽象工厂模式

三,抽象工厂模式(Abstract Factory)

这里的一系列产品,是一个 产品族 的概念,接下来我们使用抽象工厂来实现灵活的扩展产品族

  • 我们先定义一个 抽象工厂 AbstractFactory,并且此类中,有以下三个抽象方法
1
2
3
abstract Food createFood();				// 创建食物
abstract Vehicle createVehicle(); // 创建交通工具
abstract Weapon createWeapon();		// 创建武器
  • 再定义两个 类型的工厂 ,都继承自 AbstractFactory,并且实现 AbstractFactory 的三个抽象方法

  • 现代人的工厂 MordernFactory

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    public class MordernFactory extends AbstractFactory{
        @Override
        Food createFood() {
            return new Bread();
        }
        
        @Override
        Vehicle createVehicle() {
            return new Car();
        }
        
        @Override
        Weapon createWeapon() {
            return new AK47();
        }
    }
    
  • 魔法世界的人的工厂 MagicFactory

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    public class MagicFactory extends AbstractFactory {
        @Override
        Food createFood() {
            return new MushRoom();
        }
        
        @Override
        Vehicle createVehicle() {
            return new Broom();
        }
        
        @Override
        Weapon createWeapon() {
            return new MagicStick();
        }
    }
    
  • 定义三个 抽象类

    • Food 抽象的食物类, 并且其中有 eat() 抽象方法
      • 使MushRoomBread 都继承 Food。并且实现 eat() 方法
    • Weapon 抽象的武器类,并且其中有 attack() 抽象方法
      • 使AK47MagicStick都继承自 Weapon。并且实现 attack() 方法
    • Vehicle 抽象的交通工具类,并且有 go() 抽象方法
      • 使CarBroom 都继承自 Vehile。 并且实现 go() 方法
  • 在main函数中使用时,我们只需要,使用对应的具体的工厂,调用方法即可.

    1
    2
    3
    4
    5
    6
    7
    
        public static void main(String[] args) {
    //        AbstractFactory abstractFactory = new MagicFactory();
            AbstractFactory abstractFactory = new MordernFactory();
            abstractFactory.createFood().eat();
            abstractFactory.createVehicle().go();
            abstractFactory.createWeapon().attack();
        }
    
  • 以上就是,三种工厂模式的使用例子。

总结

以上三种工厂模式有什么优缺点呢?

  • 工厂方法,方便的是产品的扩展
    • 优点 : 增加新的产品类时无须修改现有系统,并封装了产品对象的创建细节,系统具有良好的灵活性和可扩展性
    • 缺点 : 在于增加新产品的同时需要增加新的工厂,导致系统类的个数成对增加,在一定程度上增加了系统的复杂性。
  • 抽象工厂方法,方便的是产品族的扩展
    • 优点 : 增加新的工厂和产品族容易
    • 缺点 : 增加新的产品等级结构麻烦
  • 两者都有自己的局限性