设计模式——工厂模式
简介
通过工厂方法创建对象,而不是直接使用构造函数。主要优点是它有助于解耦(Decoupling)不同部分之间的依赖关系。符合开闭原则:扩展开放,对修改关闭。
- 降低直接依赖
工厂模式通过引入一个工厂类,将对象的创建过程从客户端代码中分离出来。客户端代码不再直接依赖于具体的对象构造方法,而是依赖于工厂方法。这意味着客户端不需要了解如何创建对象或对象的具体类,只需要知道如何与工厂交互,从而减少了直接依赖。 - 切换实现
工厂模式使得在不修改客户端代码的情况下可以轻松切换具体对象的实现。如果需要更换或升级一个类,只需要修改工厂类中的具体创建方法,而不需要修改调用该类的客户端代码。 - 封装创建逻辑
工厂模式将对象的创建逻辑封装到一个工厂类中,这样客户端不需要关心对象创建的复杂性,只需调用工厂方法即可。这有助于隐藏对象创建的细节,提高了代码的抽象级别。 - 解除紧耦合
通过使用工厂模式,客户端与具体对象之间的耦合性减小了,因为客户端只需要依赖于工厂接口而不是具体的对象。这种解耦有助于提高代码的可维护性,降低了代码的脆弱性,因为修改具体对象的实现不会影响客户端代码。
简单工厂模式
简介
所有的产品都共有一个工厂,如果新增产品,则需要修改代码,违反开闭原则。是一种编程习惯,可以借鉴这种编程思路。
简单工厂包含如下角色:
- 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品 :实现或者继承抽象产品的子类。
- 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
示例
需求:设计一个咖啡店点餐系统。
设计一个咖啡类(Coffee),并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】);再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能。
// 咖啡抽象类
abstract class Coffee {
protected String name;
public String getName() {
return name;
}
public abstract double cost();
}
// 具体咖啡类 - 美式咖啡
class AmericanCoffee extends Coffee {
public AmericanCoffee() {
name = "美式咖啡";
}
@Override
public double cost() {
return 5.0;
}
}
// 具体咖啡类 - 拿铁咖啡
class LatteCoffee extends Coffee {
public LatteCoffee() {
name = "拿铁咖啡";
}
@Override
public double cost() {
return 7.0;
}
}
// 咖啡店类
class CoffeeStore {
// 使用简单工厂模式来创建咖啡
public Coffee orderCoffee(String type) {
Coffee coffee = null;
if (type.equals("美式咖啡")) {
coffee = new AmericanCoffee();
} else if (type.equals("拿铁咖啡")) {
coffee = new LatteCoffee();
} else {
System.out.println("抱歉,我们不提供您所点的咖啡类型");
}
if (coffee != null) {
System.out.println("制作一杯" + coffee.getName());
System.out.println("价格:" + coffee.cost() + "元");
}
return coffee;
}
}
public class CoffeeShopExample {
public static void main(String[] args) {
CoffeeStore coffeeStore = new CoffeeStore();
Coffee coffee1 = coffeeStore.orderCoffee("美式咖啡");
Coffee coffee2 = coffeeStore.orderCoffee("拿铁咖啡");
Coffee coffee3 = coffeeStore.orderCoffee("卡布奇诺");
// 输出:
// 制作一杯美式咖啡
// 价格:5.0元
// 制作一杯拿铁咖啡
// 价格:7.0元
// 抱歉,我们不提供您所点的咖啡类型
}
}
工厂方法模式
简介
给每个产品都提供了一个工厂,让工厂专门负责对应的产品的生产,遵循开闭原则(项目中用的最多)。
工厂方法模式的主要角色:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
优缺点
优点——
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点——
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
示例

// 咖啡抽象类
abstract class Coffee {
protected String name;
public String getName() {
return name;
}
public abstract double cost();
}
// 具体咖啡类 - 美式咖啡
class AmericanCoffee extends Coffee {
public AmericanCoffee() {
name = "美式咖啡";
}
@Override
public double cost() {
return 5.0;
}
}
// 具体咖啡类 - 拿铁咖啡
class LatteCoffee extends Coffee {
public LatteCoffee() {
name = "拿铁咖啡";
}
@Override
public double cost() {
return 7.0;
}
}
// 咖啡工厂接口
interface CoffeeFactory {
Coffee createCoffee();
}
// 具体工厂 - 生产美式咖啡
class AmericanCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
// 具体工厂 - 生产拿铁咖啡
class LatteCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
}
// 咖啡店类
class CoffeeStore {
// 咖啡店接收一个工厂对象,用于点咖啡
private CoffeeFactory factory;
public CoffeeStore(CoffeeFactory factory) {
this.factory = factory;
}
// 点咖啡
public Coffee orderCoffee() {
Coffee coffee = factory.createCoffee();
System.out.println("制作一杯" + coffee.getName());
System.out.println("价格:" + coffee.cost() + "元");
return coffee;
}
}
public class CoffeeShopFactoryMethodExample {
public static void main(String[] args) {
// 创建美式咖啡工厂
CoffeeFactory americanCoffeeFactory = new AmericanCoffeeFactory();
// 创建拿铁咖啡工厂
CoffeeFactory latteCoffeeFactory = new LatteCoffeeFactory();
// 在美式咖啡店点咖啡
CoffeeStore americanCoffeeStore = new CoffeeStore(americanCoffeeFactory);
Coffee coffee1 = americanCoffeeStore.orderCoffee();
// 在拿铁咖啡店点咖啡
CoffeeStore latteCoffeeStore = new CoffeeStore(latteCoffeeFactory);
Coffee coffee2 = latteCoffeeStore.orderCoffee();
// 输出:
// 制作一杯美式咖啡
// 价格:5.0元
// 制作一杯拿铁咖啡
// 价格:7.0元
}
}
每个咖啡类型都有对应的工厂类,客户端可以选择使用不同的工厂来点不同类型的咖啡,而不需要直接依赖于具体的咖啡类。这种方式更符合开放-封闭原则,允许轻松扩展系统以支持新的咖啡类型,同时保持了客户端与具体咖啡对象之间的解耦。
抽象工厂模式
简介
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品(一般企业开发中使用较少)。
如果有多个纬度的产品需要配合生产时,优先建议采用抽象工厂(工厂的工厂)。
优缺点
优点——
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点——
- 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
示例
需求:现咖啡店业务发生改变,不仅要生产咖啡还要生产甜点。
- 同一个产品等级(产品分类)
- 咖啡:拿铁咖啡、美式咖啡
- 甜点:提拉米苏、抹茶慕斯
- 同一个风味,就是同一个产品族(相当于同一个品牌)
- 美式风味:美式咖啡、抹茶慕斯
- 意大利风味:拿铁咖啡、提拉米苏

// 咖啡抽象类
abstract class Coffee {
protected String name;
protected String flavor;
public String getName() {
return name;
}
public String getFlavor() {
return flavor;
}
public abstract double cost();
}
// 具体咖啡类
class LatteCoffee extends Coffee {
public LatteCoffee() {
name = "拿铁咖啡";
flavor = "意大利风味";
}
@Override
public double cost() {
return 7.0;
}
}
class AmericanCoffee extends Coffee {
public AmericanCoffee() {
name = "美式咖啡";
flavor = "美式风味";
}
@Override
public double cost() {
return 5.0;
}
}
// 甜点抽象类
abstract class Dessert {
protected String name;
protected String flavor;
public String getName() {
return name;
}
public String getFlavor() {
return flavor;
}
public abstract double cost();
}
// 具体甜点类
class Tiramisu extends Dessert {
public Tiramisu() {
name = "提拉米苏";
flavor = "意大利风味";
}
@Override
public double cost() {
return 8.0;
}
}
class MatchaMousse extends Dessert {
public MatchaMousse() {
name = "抹茶慕斯";
flavor = "美式风味";
}
@Override
public double cost() {
return 6.0;
}
}
// 咖啡工厂接口
interface CoffeeFactory {
Coffee createCoffee();
}
// 具体咖啡工厂类
class LatteCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
}
class AmericanCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
// 甜点工厂接口
interface DessertFactory {
Dessert createDessert();
}
// 具体甜点工厂类
class TiramisuFactory implements DessertFactory {
@Override
public Dessert createDessert() {
return new Tiramisu();
}
}
class MatchaMousseFactory implements DessertFactory {
@Override
public Dessert createDessert() {
return new MatchaMousse();
}
}
class CoffeeShop {
private CoffeeFactory coffeeFactory;
private DessertFactory dessertFactory;
public CoffeeShop(CoffeeFactory coffeeFactory, DessertFactory dessertFactory) {
this.coffeeFactory = coffeeFactory;
this.dessertFactory = dessertFactory;
}
public void orderCoffeeAndDessert() {
Coffee coffee = coffeeFactory.createCoffee();
Dessert dessert = dessertFactory.createDessert();
System.out.println("点了一杯" + coffee.getFlavor() + "的" + coffee.getName() +
"和一个" + dessert.getFlavor() + "的" + dessert.getName());
System.out.println("总价格:" + (coffee.cost() + dessert.cost()) + "元");
}
}
public class CoffeeShopAbstractFactoryExample {
public static void main(String[] args) {
// 创建意大利风味的咖啡店
CoffeeFactory italianCoffeeFactory = new LatteCoffeeFactory();
DessertFactory italianDessertFactory = new TiramisuFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory, italianDessertFactory);
italianCoffeeShop.orderCoffeeAndDessert();
// 创建美式风味的咖啡店
CoffeeFactory americanCoffeeFactory = new AmericanCoffeeFactory();
DessertFactory americanDessertFactory = new MatchaMousseFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory, americanDessertFactory);
americanCoffeeShop.orderCoffeeAndDessert();
}
}
应用场景
依赖注入(Dependency Injection)
Spring Framework的核心特性之一是依赖注入(DI),它通过工厂模式实现了将对象的创建和管理从应用程序代码中解耦。Spring容器充当了工厂的角色,负责创建和管理应用程序中的各种Bean(组件)。通过配置,可以指定使用哪个工厂(Bean的定义),以及如何创建和注入依赖关系。
Bean工厂
Spring框架中的BeanFactory是一个工厂接口,它允许根据Bean的名称或类型来获取Bean实例。BeanFactory的实现通常是一个工厂模式的典型例子,根据配置文件或注解中的描述来创建和管理Bean。
AOP代理工厂
Spring AOP(面向切面编程)通常使用工厂模式来创建代理对象。例如,Spring使用工厂模式来创建JDK动态代理或CGLIB代理对象,以便在切面方法周围织入横切关注点。
数据源管理
Spring框架支持多种数据源,包括连接池数据源、JNDI数据源等。这些数据源的创建和管理都使用了工厂模式,通过配置选择合适的工厂来创建数据源。
消息队列连接工厂
Spring框架对消息队列系统(如ActiveMQ、RabbitMQ)的支持也使用了工厂模式。它提供了连接工厂和会话工厂等工厂接口,以便创建与消息队列的连接和会话。
视图解析器工厂
Spring MVC框架中使用了工厂模式来创建视图解析器,用于解析视图名称并生成视图对象,从而实现控制器的视图解析和渲染。

浙公网安备 33010602011771号