工厂模式在软件设计中是非常重要的,它提供了一种灵活的方法来创建对象,有助于降低代码的耦合度,提高代码的可维护性和可扩展性。同样也是面试中的高频考点。
什么是工厂模式
工厂模式是一种常用的软件设计模式,用于创建对象。它属于创建型设计模式,主要用于处理对象的创建而无需指定具体类。工厂模式通过定义一个创建对象的接口,但让子类决定实例化哪个类来创建对象。这样,客户端代码就不需要知道实际要实例化的类,只需要知道使用的是工厂方法即可。
工厂模式的几个重要优点:
-
降低耦合度:工厂模式将对象的创建和使用分离开来,客户端代码不需要直接依赖于具体的类,而是依赖于抽象的接口或基类,从而减少了对象之间的耦合度。
-
提高可维护性:由于工厂模式使得对象的创建集中在工厂类中,当需要修改对象创建逻辑时,只需要修改工厂类而不影响客户端代码,这样就提高了代码的可维护性。
-
增加灵活性:工厂模式可以根据需求灵活地创建不同类型的对象,而且可以通过配置或者运行时动态决定创建哪种类型的对象,从而增加了系统的灵活性。
-
提高代码的可扩展性:当需要添加新的产品类时,只需要添加相应的具体产品类和对应的具体工厂类,而不需要修改现有的代码,这样就提高了系统的可扩展性。
-
促进代码的重用:工厂模式可以将对象的创建逻辑封装在工厂类中,这样可以在不同的地方重复使用相同的创建逻辑,提高了代码的重用性。
工厂模式有三种主要的实现方式:
- 简单工厂模式(Simple Factory Pattern):由一个工厂类根据传入的参数,决定创建哪一种产品类的实例。这种模式只有一个工厂类。
- 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,但是将实际创建工作推迟到子类中。每个子类都可以实现这个工厂方法以提供对象的实例化。
- 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。通常,这种模式涉及一个工厂接口和多个具体工厂类,每个具体工厂类负责实例化一组相关的对象。
这些工厂模式的选择取决于具体的需求和设计情况。在大型软件系统中,工厂模式可以帮助降低代码的耦合度,提高代码的可维护性和可扩展性。
简单工厂模式
简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。比如,一台咖啡机就可以理解为一个工厂模式,你只需要按下想喝的咖啡品类的按钮(摩卡或拿铁),它就会给你生产一杯相应的咖啡,你不需要管它内部的具体实现,只要
告诉它你的需求即可。
优点:
- 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象;
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑;
产品类型较多时,工厂的创建逻辑可能过于复杂,一旦出错可能造成所有产品的创建失败,
不利于系统的维护。
实现
这里实现一个简单的咖啡机
// 咖啡接口
interface Coffee {
void brew();
}
// 具体的咖啡类:美式咖啡
class Americano implements Coffee {
@Override
public void brew() {
System.out.println("冲一杯美式咖啡");
}
}
// 具体的咖啡类:拿铁咖啡
class Latte implements Coffee {
@Override
public void brew() {
System.out.println("冲一杯拿铁咖啡");
}
}
// 咖啡机工厂类
class CoffeeMachine {
// 根据咖啡类型生产咖啡
public Coffee makeCoffee(String type) {
if (type.equalsIgnoreCase("americano")) {
return new Americano();
} else if (type.equalsIgnoreCase("latte")) {
return new Latte();
} else {
System.out.println("不支持的咖啡类型");
return null;
}
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
CoffeeMachine coffeeMachine = new CoffeeMachine();
// 制作美式咖啡
Coffee americano = coffeeMachine.makeCoffee("americano");
if (americano != null) {
americano.brew();
}
// 制作拿铁咖啡
Coffee latte = coffeeMachine.makeCoffee("latte");
if (latte != null) {
latte.brew();
}
// 制作不支持的咖啡类型
Coffee cappuccino = coffeeMachine.makeCoffee("cappuccino");
if (cappuccino != null) {
cappuccino.brew();
}
}
}
抽象工厂
抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。
比如,以上面的咖啡工厂为例,某天我的口味突然变了,不想喝咖啡了想喝啤酒,这个时候如果直接修改简单工厂里面的代码,这种做法不但不够优雅,也不符合软件设计的“开闭原则” ,因为每次新增品类都要修改原来的代码。这个时候就可以使用抽象工厂类了,抽象工厂里只声明方法,具体的实现交给子类(子工厂)去实现,这个时候再有新增品类的需求,只需要新创建代码即可。
// 抽象产品接口:饮料
interface Drink {
void consume();
}
// 具体产品:咖啡
class Coffee implements Drink {
@Override
public void consume() {
System.out.println("喝咖啡");
}
}
// 具体产品:啤酒
class Beer implements Drink {
@Override
public void consume() {
System.out.println("喝啤酒");
}
}
// 抽象工厂接口:饮料工厂
interface DrinkFactory {
Drink createDrink();
}
// 具体工厂:咖啡工厂
class CoffeeFactory implements DrinkFactory {
@Override
public Drink createDrink() {
return new Coffee();
}
}
// 具体工厂:啤酒工厂
class BeerFactory implements DrinkFactory {
@Override
public Drink createDrink() {
return new Beer();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
// 制作咖啡
DrinkFactory coffeeFactory = new CoffeeFactory();
Drink coffee = coffeeFactory.createDrink();
coffee.consume(); // 输出:喝咖啡
// 制作啤酒
DrinkFactory beerFactory = new BeerFactory();
Drink beer = beerFactory.createDrink();
beer.consume(); // 输出:喝啤酒
}
}
spring和工厂模式
在 Spring 框架中,工厂模式被广泛应用。Spring 提供了多种类型的工厂模式,其中最常见的是上面提到的工厂方法模式和抽象工厂模式的应用。
-
工厂方法模式(Factory Method Pattern):
Spring 中最常见的工厂模式应用就是工厂方法模式。在 Spring 中,Bean 的创建和管理由容器来完成,容器根据配置文件中的信息来创建 Bean,并将它们装配到需要它们的地方。这里的 BeanFactory 就是一个典型的工厂,它负责根据配置信息来创建具体的 Bean 实例。例如,ApplicationContext 接口就是 Spring 的 IoC 容器,它负责管理 Bean 的生命周期,并且提供了多种获取 Bean 实例的方法,比如
getBean()
方法。 -
抽象工厂模式(Abstract Factory Pattern):
Spring 还使用了抽象工厂模式来创建相关的 Bean。在 Spring 中,BeanFactory 可以是一个具体工厂,负责创建一组相关的 Bean,这些 Bean 可能有一定的关联关系。例如,DataSource 接口就是 Spring 中的一个抽象工厂,它定义了获取数据库连接的方法,而具体的实现可以是 BasicDataSource、DriverManagerDataSource 等,这些具体的实现都是相关的,它们都用于创建数据库连接。
工厂模式帮助我们将对象的创建和使用分离开来,从而提高了代码的灵活性和可维护性。
总结
综上所述,工厂模式在软件设计中具有重要的作用,特别是在大型软件系统中,它可以帮助提高代码的质量和可维护性,减少代码的重复和耦合,从而使得系统更加灵活和可扩展。