上一篇讲单例,解决的是“一个类只留一个对象”。
这一篇换个问题:项目里的对象越来越多,new 到底该写在哪儿?
先别急着记“开闭原则”这些词。咱去狗哥的饮品店站一会儿,看完再回代码里。
🍊 顾客只管点单
你去店里说:“来杯拿铁。”
正常情况下,店员不会把围裙和咖啡豆递过来,让你自己磨。顾客负责点单,后厨负责做,分工挺明白。

程序里也能这么分。
业务代码提出“我要一杯拿铁”,专门创建对象的代码负责 new Latte()。这个负责创建对象的地方,就是我们今天说的工厂。
先看直接 new 的写法
饮品店刚开张,只有美式和拿铁。点单方法可能会写成这样:
public Coffee order(String type) {
if ("americano".equals(type)) {
return new Americano();
}
if ("latte".equals(type)) {
return new Latte();
}
throw new IllegalArgumentException("没有这种咖啡");
}
两种咖啡时,这段代码没啥大毛病,也很好懂。
可菜单继续加,卡布奇诺、摩卡、燕麦拿铁都来了。每加一种,点单方法就得回来添判断、添 new。
麻烦不在 new 这个单词,而在于点单代码知道的创建细节越来越多。
哪天拿铁创建前还要准备牛奶、糖浆和杯型,这个方法会越写越长。用济南话说,有点不大利索了。
把咖啡先归到一类
先写一个 Coffee 接口。现在只放一个 getName(),够例子用就行。
Coffee.java
public interface Coffee {
String getName();
}
美式和拿铁都实现它。
Americano.java
public class Americano implements Coffee {
@Override
public String getName() {
return "Americano";
}
}
Latte.java
public class Latte implements Coffee {
@Override
public String getName() {
return "Latte";
}
}
这一步不神秘。就是让两种咖啡都有同一个类型,以后代码可以先用 Coffee 接住它们。
再给工厂定个规矩
接着写 CoffeeFactory。
CoffeeFactory.java
public interface CoffeeFactory {
Coffee createCoffee();
}
它只定了一条规矩:咖啡工厂都得会创建咖啡。
至于创建美式还是拿铁,交给具体工厂。
AmericanoFactory.java
public class AmericanoFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new Americano();
}
}
LatteFactory.java
public class LatteFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new Latte();
}
}
代码里的角色看着多,其实就是两组对应关系。
Coffee 管“咖啡能做什么”,CoffeeFactory 管“咖啡怎么创建”。
书上会把它们叫产品、具体产品、工厂、具体工厂。第一遍不用背,能看懂谁创建谁就行。
跑起来看看
最后写一个测试入口。
FactoryMethodDemo.java
public class FactoryMethodDemo {
public static void main(String[] args) {
makeCoffee(new AmericanoFactory());
makeCoffee(new LatteFactory());
}
private static void makeCoffee(CoffeeFactory factory) {
Coffee coffee = factory.createCoffee();
System.out.println("Coffee ready: " + coffee.getName());
}
}
运行后会看到:
Coffee ready: Americano
Coffee ready: Latte
重点看 makeCoffee()。
它接收的是 CoffeeFactory,没有把参数写死成 AmericanoFactory。传进来哪家工厂,它就让哪家工厂创建咖啡。
这里的 new 没有消失,只是挪到了更合适的地方。
**业务流程不再负责具体对象的创建,工厂把这部分接了过去。**这就是工厂方法模式最值得记住的地方。
新增一种咖啡,会改哪里
假设店里增加卡布奇诺。
我们可以新增 Cappuccino,再新增一个 CappuccinoFactory。原来的 makeCoffee() 仍然接收 CoffeeFactory,不用为了新品改方法内部。
这里有个容易说过头的地方。
工厂方法不代表新增产品后,一行旧代码都不用改。菜单、配置或者选择工厂的地方,还是得知道来了新品。
它减少的是创建逻辑对原流程的影响。别把它理解成魔法,恁简单看就行。
也别见到 new 就建工厂
工厂会多出接口和类。
如果程序只有一两个简单对象,创建方式以后也不变,直接 new 更省事。为了套模式建一堆文件,反而不好找代码。
我会在这几种情况下考虑工厂:产品种类还会增加,创建前要准备不少东西,或者业务代码不该知道具体实现。
判断标准不用背。创建对象这块开始变乱了,再把它单独收进工厂。
🐾 狗哥捋一下
这一篇的代码稍微比单例多,但主线没变。
顾客负责点单,工厂负责创建,最后交回一个 Coffee。不同工厂创建不同咖啡,调用代码只认统一的 CoffeeFactory。
自己敲一遍时,可以先只写美式。跑通以后,再加拿铁工厂。一步一步来,不容易绕木乱。
下一篇准备聊抽象工厂模式。它和今天这个名字很像,但解决的问题不一样。到时候还是从生活例子往代码里走。
#Java #设计模式 #工厂方法模式 #Java基础 #后端开发 #程序员入门