欢迎光临
我们一直在努力

设计模式:工厂方法模式

工厂方法模式:别再到处 new 对象,让子类决定该创建谁

目录

  • new 有什么问题
  • 工厂方法模式是什么
  • 代码实现:物流系统的运输方式
  • 工厂方法模式和简单工厂模式的区别
  • 实际应用
  • 小结

new 有什么问题

假设你接手了一个电商系统的订单模块,代码里到处写着这种东西:

// 订单服务里
AlipayPayment payment = new AlipayPayment();
payment.pay(order.getAmount());

// 退款服务里
AlipayPayment payment = new AlipayPayment();
payment.refund(order.getAmount());

// 对账服务里
AlipayPayment payment = new AlipayPayment();
payment.reconcile(order.getRecords());

三个服务都直接 new AlipayPayment()。现在需求来了:接入微信支付。你得满项目找 new AlipayPayment(),逐个判断该换成 new WechatPayment() 还是保留。这可得找到什么时候啊。

问题的根源在于:调用方既关心"用什么",又关心"怎么造"。 这两件事耦合在一起,改任何一个都得动另一个。那如果把"怎么造"这件事抽出去,调用方只管使用呢?

工厂方法模式是什么

工厂方法模式:定义一个创建对象的抽象方法,让子类决定具体创建谁。

类比一下点外卖的场景。你在美团上点了一份黄焖鸡,你只关心"下单、等餐、收货"这个流程。至于这道菜是哪个厨师做的、用的哪个灶台、从哪个锅里盛出来的,你完全不关心。平台负责把"做一份黄焖鸡"这个需求派给合适的商家,商家决定怎么做。

调用方通过工厂方法拿到对象,不直接 new。具体创建谁,交由子类说了算。

代码实现:物流系统的运输方式

用一个物流系统的例子来走一遍完整实现。系统需要支持卡车、轮船、飞机三种运输方式,未来还会加更多。

产品接口

先定义所有运输方式的共同接口:

public interface Transport {
String deliver();
}

调用方只认这个接口。至于底层是卡车还是飞机,它不知道也并不关注。

具体产品

三种运输方式各自实现接口:

public class Truck implements Transport {
@Override
public String deliver() {
return "卡车陆运货物";
}
}

public class Ship implements Transport {
@Override
public String deliver() {
return "轮船海运货物";
}
}

public class Airplane implements Transport {
@Override
public String deliver() {
return "飞机空运货物";
}
}

抽象创建者

这是工厂方法模式最关键的部分。创建者是一个抽象类,它定义了工厂方法,但不实现它:

public abstract class Logistics {
// 定义抽象方法:工厂方法:返回类型是接口,不是具体类
protected abstract Transport createTransport();

// 业务逻辑:只依赖接口
public void shipGoods() {
Transport transport = createTransport();
System.out.println(transport.deliver());
}
}

createTransport() 是抽象的,父类只说"给我一个运输工具",至于是什么,由子类定。shipGoods() 是业务方法,它拿到的是 Transport 接口,永远不碰具体类。

具体创建者

子类重写工厂方法,各自决定创建什么:

public class RoadLogistics extends Logistics {
@Override
protected Transport createTransport() {
return new Truck();
}
}

public class SeaLogistics extends Logistics {
@Override
protected Transport createTransport() {
return new Ship();
}
}

public class AirLogistics extends Logistics {
@Override
protected Transport createTransport() {
return new Airplane();
}
}

每个子类只管一件事:创建哪个产品。它不关心产品创建之后怎么使用。

使用

Logistics logistics = new RoadLogistics();
logistics.shipGoods(); // 卡车陆运货物

logistics = new SeaLogistics();
logistics.shipGoods(); // 轮船海运货物

调用方决定"用哪个子类",子类决定"创建哪个产品"。创建决策从一行 new 变成了一个可扩展的继承体系。

现在要加火箭运输?加两个类就行:Rocket implements Transport,RocketLogistics extends Logistics。已有代码一行不改。

整个流程串起来长这样:

在这里插入图片描述

工厂方法模式和简单工厂模式的区别

你可能会说:搞这么复杂干嘛,直接写一个工厂类不可以吗?

public class TransportFactory {
public static Transport create(String type) {
switch (type) {
case "truck": return new Truck();
case "ship": return new Ship();
case "airplane": return new Airplane();
default: throw new RuntimeException("不支持:" + type);
}
}
}

简单工厂模式确实可用。但两者有本质区别:

简单工厂是把所有创建逻辑塞进一个 switch,工厂方法是把每个创建逻辑拆到各自的子类里。

什么时候适合用简单工厂?产品就两三种并且创建逻辑简单、基本不会扩展的时候,简单工厂更直接,就没必要搞继承。

什么时候用工厂方法?产品类型会持续增长、创建逻辑各有差异、需要符合开闭原则的时候,工厂方法则更加合适。

小结

工厂方法模式解决的问题很直接:别让调用方自己 new 对象。 把创建逻辑抽到一个抽象方法里,让子类决定创建什么,调用方只管使用。这样新增产品只需要增加实现类和对应的创建子类,老代码无需改动。

赞(0)
未经允许不得转载:171主机测评 » 设计模式:工厂方法模式
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址