工厂模式详解:简单工厂、工厂方法与抽象工厂

工厂模式解决的不是"怎么 new 一个对象"这么简单。它真正解决的是:对象创建逻辑变化时,业务代码要不要跟着改。

如果对象类型很少,直接 new 没什么问题;一旦产品类型变多、创建过程变复杂、调用方到处写 if-else,代码就会开始腐烂。工厂模式就是把"创建什么对象"的决策从业务流程里拆出去。

为什么需要工厂模式

先看一个咖啡下单场景。咖啡店根据类型创建不同咖啡:

java 复制代码
public Coffee orderCoffee(String type) {
    Coffee coffee;
    if ("latte".equals(type)) {
        coffee = new LatteCoffee();
    } else if ("american".equals(type)) {
        coffee = new AmericanCoffee();
    } else {
        throw new IllegalArgumentException("unsupported coffee type");
    }

    coffee.addMilk();
    coffee.addSugar();
    return coffee;
}

这段代码的问题不在于能不能跑,而在于它把两件事揉在了一起:

  1. 根据类型创建咖啡。
  2. 对咖啡做统一加工。

当你新增摩卡咖啡时,orderCoffee 必须修改。新增越多,这个方法越像一张对象创建清单。
#mermaid-svg-JRyuJ12aB57GXxxs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JRyuJ12aB57GXxxs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JRyuJ12aB57GXxxs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JRyuJ12aB57GXxxs .error-icon{fill:#552222;}#mermaid-svg-JRyuJ12aB57GXxxs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JRyuJ12aB57GXxxs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JRyuJ12aB57GXxxs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JRyuJ12aB57GXxxs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JRyuJ12aB57GXxxs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JRyuJ12aB57GXxxs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JRyuJ12aB57GXxxs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JRyuJ12aB57GXxxs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JRyuJ12aB57GXxxs .marker.cross{stroke:#333333;}#mermaid-svg-JRyuJ12aB57GXxxs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JRyuJ12aB57GXxxs p{margin:0;}#mermaid-svg-JRyuJ12aB57GXxxs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JRyuJ12aB57GXxxs .cluster-label text{fill:#333;}#mermaid-svg-JRyuJ12aB57GXxxs .cluster-label span{color:#333;}#mermaid-svg-JRyuJ12aB57GXxxs .cluster-label span p{background-color:transparent;}#mermaid-svg-JRyuJ12aB57GXxxs .label text,#mermaid-svg-JRyuJ12aB57GXxxs span{fill:#333;color:#333;}#mermaid-svg-JRyuJ12aB57GXxxs .node rect,#mermaid-svg-JRyuJ12aB57GXxxs .node circle,#mermaid-svg-JRyuJ12aB57GXxxs .node ellipse,#mermaid-svg-JRyuJ12aB57GXxxs .node polygon,#mermaid-svg-JRyuJ12aB57GXxxs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JRyuJ12aB57GXxxs .rough-node .label text,#mermaid-svg-JRyuJ12aB57GXxxs .node .label text,#mermaid-svg-JRyuJ12aB57GXxxs .image-shape .label,#mermaid-svg-JRyuJ12aB57GXxxs .icon-shape .label{text-anchor:middle;}#mermaid-svg-JRyuJ12aB57GXxxs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JRyuJ12aB57GXxxs .rough-node .label,#mermaid-svg-JRyuJ12aB57GXxxs .node .label,#mermaid-svg-JRyuJ12aB57GXxxs .image-shape .label,#mermaid-svg-JRyuJ12aB57GXxxs .icon-shape .label{text-align:center;}#mermaid-svg-JRyuJ12aB57GXxxs .node.clickable{cursor:pointer;}#mermaid-svg-JRyuJ12aB57GXxxs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JRyuJ12aB57GXxxs .arrowheadPath{fill:#333333;}#mermaid-svg-JRyuJ12aB57GXxxs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JRyuJ12aB57GXxxs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JRyuJ12aB57GXxxs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JRyuJ12aB57GXxxs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JRyuJ12aB57GXxxs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JRyuJ12aB57GXxxs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JRyuJ12aB57GXxxs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JRyuJ12aB57GXxxs .cluster text{fill:#333;}#mermaid-svg-JRyuJ12aB57GXxxs .cluster span{color:#333;}#mermaid-svg-JRyuJ12aB57GXxxs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JRyuJ12aB57GXxxs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JRyuJ12aB57GXxxs rect.text{fill:none;stroke-width:0;}#mermaid-svg-JRyuJ12aB57GXxxs .icon-shape,#mermaid-svg-JRyuJ12aB57GXxxs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JRyuJ12aB57GXxxs .icon-shape p,#mermaid-svg-JRyuJ12aB57GXxxs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JRyuJ12aB57GXxxs .icon-shape .label rect,#mermaid-svg-JRyuJ12aB57GXxxs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JRyuJ12aB57GXxxs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JRyuJ12aB57GXxxs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JRyuJ12aB57GXxxs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} latte
american
mocha
CoffeeStore.orderCoffee
type 是什么
new LatteCoffee
new AmericanCoffee
new MochaCoffee
加奶和加糖

工厂模式的方向是:让咖啡店只关心点单流程,把创建咖啡的细节交给工厂。

简单工厂

简单工厂不是 GoF 设计模式里的标准模式,更像一种常用编码习惯。它把对象创建逻辑集中到一个工厂类里。

java 复制代码
public class SimpleCoffeeFactory {

    public Coffee createCoffee(String type) {
        if ("latte".equals(type)) {
            return new LatteCoffee();
        }
        if ("american".equals(type)) {
            return new AmericanCoffee();
        }
        throw new IllegalArgumentException("unsupported coffee type");
    }
}

咖啡店变成这样:

java 复制代码
public class CoffeeStore {
    private final SimpleCoffeeFactory factory = new SimpleCoffeeFactory();

    public Coffee orderCoffee(String type) {
        Coffee coffee = factory.createCoffee(type);
        coffee.addMilk();
        coffee.addSugar();
        return coffee;
    }
}

结构图如下:
#mermaid-svg-yhLvuq0g2s5y4G7j{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yhLvuq0g2s5y4G7j .error-icon{fill:#552222;}#mermaid-svg-yhLvuq0g2s5y4G7j .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yhLvuq0g2s5y4G7j .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yhLvuq0g2s5y4G7j .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yhLvuq0g2s5y4G7j .marker.cross{stroke:#333333;}#mermaid-svg-yhLvuq0g2s5y4G7j svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yhLvuq0g2s5y4G7j p{margin:0;}#mermaid-svg-yhLvuq0g2s5y4G7j .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yhLvuq0g2s5y4G7j .cluster-label text{fill:#333;}#mermaid-svg-yhLvuq0g2s5y4G7j .cluster-label span{color:#333;}#mermaid-svg-yhLvuq0g2s5y4G7j .cluster-label span p{background-color:transparent;}#mermaid-svg-yhLvuq0g2s5y4G7j .label text,#mermaid-svg-yhLvuq0g2s5y4G7j span{fill:#333;color:#333;}#mermaid-svg-yhLvuq0g2s5y4G7j .node rect,#mermaid-svg-yhLvuq0g2s5y4G7j .node circle,#mermaid-svg-yhLvuq0g2s5y4G7j .node ellipse,#mermaid-svg-yhLvuq0g2s5y4G7j .node polygon,#mermaid-svg-yhLvuq0g2s5y4G7j .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yhLvuq0g2s5y4G7j .rough-node .label text,#mermaid-svg-yhLvuq0g2s5y4G7j .node .label text,#mermaid-svg-yhLvuq0g2s5y4G7j .image-shape .label,#mermaid-svg-yhLvuq0g2s5y4G7j .icon-shape .label{text-anchor:middle;}#mermaid-svg-yhLvuq0g2s5y4G7j .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yhLvuq0g2s5y4G7j .rough-node .label,#mermaid-svg-yhLvuq0g2s5y4G7j .node .label,#mermaid-svg-yhLvuq0g2s5y4G7j .image-shape .label,#mermaid-svg-yhLvuq0g2s5y4G7j .icon-shape .label{text-align:center;}#mermaid-svg-yhLvuq0g2s5y4G7j .node.clickable{cursor:pointer;}#mermaid-svg-yhLvuq0g2s5y4G7j .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yhLvuq0g2s5y4G7j .arrowheadPath{fill:#333333;}#mermaid-svg-yhLvuq0g2s5y4G7j .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yhLvuq0g2s5y4G7j .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yhLvuq0g2s5y4G7j .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yhLvuq0g2s5y4G7j .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yhLvuq0g2s5y4G7j .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yhLvuq0g2s5y4G7j .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yhLvuq0g2s5y4G7j .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yhLvuq0g2s5y4G7j .cluster text{fill:#333;}#mermaid-svg-yhLvuq0g2s5y4G7j .cluster span{color:#333;}#mermaid-svg-yhLvuq0g2s5y4G7j div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yhLvuq0g2s5y4G7j .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yhLvuq0g2s5y4G7j rect.text{fill:none;stroke-width:0;}#mermaid-svg-yhLvuq0g2s5y4G7j .icon-shape,#mermaid-svg-yhLvuq0g2s5y4G7j .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yhLvuq0g2s5y4G7j .icon-shape p,#mermaid-svg-yhLvuq0g2s5y4G7j .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yhLvuq0g2s5y4G7j .icon-shape .label rect,#mermaid-svg-yhLvuq0g2s5y4G7j .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yhLvuq0g2s5y4G7j .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yhLvuq0g2s5y4G7j .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yhLvuq0g2s5y4G7j :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CoffeeStore
SimpleCoffeeFactory
LatteCoffee
AmericanCoffee
Coffee

简单工厂的好处是调用方简单,创建逻辑集中。缺点也明显:新增产品时仍然要改工厂类。

优点 缺点
调用方不直接关心具体类 新增产品要修改工厂
创建逻辑集中管理 工厂类可能越来越大
适合产品类型少的场景 不完全符合开闭原则

如果只有两三个产品,并且变化不频繁,简单工厂很实用。不要为了"设计模式"硬上更复杂的结构。

工厂方法

工厂方法进一步拆分工厂:每个产品有自己的工厂,调用方通过抽象工厂创建产品。

java 复制代码
public interface CoffeeFactory {
    Coffee createCoffee();
}
java 复制代码
public class LatteCoffeeFactory implements CoffeeFactory {
    @Override
    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}
java 复制代码
public class AmericanCoffeeFactory implements CoffeeFactory {
    @Override
    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}

咖啡店依赖抽象工厂:

java 复制代码
public class CoffeeStore {
    private final CoffeeFactory coffeeFactory;

    public CoffeeStore(CoffeeFactory coffeeFactory) {
        this.coffeeFactory = coffeeFactory;
    }

    public Coffee orderCoffee() {
        Coffee coffee = coffeeFactory.createCoffee();
        coffee.addMilk();
        coffee.addSugar();
        return coffee;
    }
}

#mermaid-svg-eG0RwPmzqnWzOYb7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eG0RwPmzqnWzOYb7 .error-icon{fill:#552222;}#mermaid-svg-eG0RwPmzqnWzOYb7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eG0RwPmzqnWzOYb7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .marker.cross{stroke:#333333;}#mermaid-svg-eG0RwPmzqnWzOYb7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eG0RwPmzqnWzOYb7 p{margin:0;}#mermaid-svg-eG0RwPmzqnWzOYb7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .cluster-label text{fill:#333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .cluster-label span{color:#333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .cluster-label span p{background-color:transparent;}#mermaid-svg-eG0RwPmzqnWzOYb7 .label text,#mermaid-svg-eG0RwPmzqnWzOYb7 span{fill:#333;color:#333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .node rect,#mermaid-svg-eG0RwPmzqnWzOYb7 .node circle,#mermaid-svg-eG0RwPmzqnWzOYb7 .node ellipse,#mermaid-svg-eG0RwPmzqnWzOYb7 .node polygon,#mermaid-svg-eG0RwPmzqnWzOYb7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eG0RwPmzqnWzOYb7 .rough-node .label text,#mermaid-svg-eG0RwPmzqnWzOYb7 .node .label text,#mermaid-svg-eG0RwPmzqnWzOYb7 .image-shape .label,#mermaid-svg-eG0RwPmzqnWzOYb7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-eG0RwPmzqnWzOYb7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eG0RwPmzqnWzOYb7 .rough-node .label,#mermaid-svg-eG0RwPmzqnWzOYb7 .node .label,#mermaid-svg-eG0RwPmzqnWzOYb7 .image-shape .label,#mermaid-svg-eG0RwPmzqnWzOYb7 .icon-shape .label{text-align:center;}#mermaid-svg-eG0RwPmzqnWzOYb7 .node.clickable{cursor:pointer;}#mermaid-svg-eG0RwPmzqnWzOYb7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .arrowheadPath{fill:#333333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eG0RwPmzqnWzOYb7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eG0RwPmzqnWzOYb7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eG0RwPmzqnWzOYb7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eG0RwPmzqnWzOYb7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eG0RwPmzqnWzOYb7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eG0RwPmzqnWzOYb7 .cluster text{fill:#333;}#mermaid-svg-eG0RwPmzqnWzOYb7 .cluster span{color:#333;}#mermaid-svg-eG0RwPmzqnWzOYb7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eG0RwPmzqnWzOYb7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eG0RwPmzqnWzOYb7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-eG0RwPmzqnWzOYb7 .icon-shape,#mermaid-svg-eG0RwPmzqnWzOYb7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eG0RwPmzqnWzOYb7 .icon-shape p,#mermaid-svg-eG0RwPmzqnWzOYb7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eG0RwPmzqnWzOYb7 .icon-shape .label rect,#mermaid-svg-eG0RwPmzqnWzOYb7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eG0RwPmzqnWzOYb7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eG0RwPmzqnWzOYb7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eG0RwPmzqnWzOYb7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CoffeeStore
CoffeeFactory
LatteCoffeeFactory
AmericanCoffeeFactory
LatteCoffee
AmericanCoffee
Coffee

新增摩卡咖啡时,不需要修改已有工厂,只要新增:

  1. MochaCoffee
  2. MochaCoffeeFactory

#mermaid-svg-DhzULBzdfehovgpA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DhzULBzdfehovgpA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DhzULBzdfehovgpA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DhzULBzdfehovgpA .error-icon{fill:#552222;}#mermaid-svg-DhzULBzdfehovgpA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DhzULBzdfehovgpA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DhzULBzdfehovgpA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DhzULBzdfehovgpA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DhzULBzdfehovgpA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DhzULBzdfehovgpA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DhzULBzdfehovgpA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DhzULBzdfehovgpA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DhzULBzdfehovgpA .marker.cross{stroke:#333333;}#mermaid-svg-DhzULBzdfehovgpA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DhzULBzdfehovgpA p{margin:0;}#mermaid-svg-DhzULBzdfehovgpA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DhzULBzdfehovgpA .cluster-label text{fill:#333;}#mermaid-svg-DhzULBzdfehovgpA .cluster-label span{color:#333;}#mermaid-svg-DhzULBzdfehovgpA .cluster-label span p{background-color:transparent;}#mermaid-svg-DhzULBzdfehovgpA .label text,#mermaid-svg-DhzULBzdfehovgpA span{fill:#333;color:#333;}#mermaid-svg-DhzULBzdfehovgpA .node rect,#mermaid-svg-DhzULBzdfehovgpA .node circle,#mermaid-svg-DhzULBzdfehovgpA .node ellipse,#mermaid-svg-DhzULBzdfehovgpA .node polygon,#mermaid-svg-DhzULBzdfehovgpA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DhzULBzdfehovgpA .rough-node .label text,#mermaid-svg-DhzULBzdfehovgpA .node .label text,#mermaid-svg-DhzULBzdfehovgpA .image-shape .label,#mermaid-svg-DhzULBzdfehovgpA .icon-shape .label{text-anchor:middle;}#mermaid-svg-DhzULBzdfehovgpA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DhzULBzdfehovgpA .rough-node .label,#mermaid-svg-DhzULBzdfehovgpA .node .label,#mermaid-svg-DhzULBzdfehovgpA .image-shape .label,#mermaid-svg-DhzULBzdfehovgpA .icon-shape .label{text-align:center;}#mermaid-svg-DhzULBzdfehovgpA .node.clickable{cursor:pointer;}#mermaid-svg-DhzULBzdfehovgpA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DhzULBzdfehovgpA .arrowheadPath{fill:#333333;}#mermaid-svg-DhzULBzdfehovgpA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DhzULBzdfehovgpA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DhzULBzdfehovgpA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DhzULBzdfehovgpA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DhzULBzdfehovgpA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DhzULBzdfehovgpA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DhzULBzdfehovgpA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DhzULBzdfehovgpA .cluster text{fill:#333;}#mermaid-svg-DhzULBzdfehovgpA .cluster span{color:#333;}#mermaid-svg-DhzULBzdfehovgpA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DhzULBzdfehovgpA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DhzULBzdfehovgpA rect.text{fill:none;stroke-width:0;}#mermaid-svg-DhzULBzdfehovgpA .icon-shape,#mermaid-svg-DhzULBzdfehovgpA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DhzULBzdfehovgpA .icon-shape p,#mermaid-svg-DhzULBzdfehovgpA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DhzULBzdfehovgpA .icon-shape .label rect,#mermaid-svg-DhzULBzdfehovgpA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DhzULBzdfehovgpA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DhzULBzdfehovgpA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DhzULBzdfehovgpA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 新增产品
新增 MochaCoffee
新增 MochaCoffeeFactory
不修改原有产品
不修改原有工厂

工厂方法的核心价值是扩展性。它更符合开闭原则:对扩展开放,对修改关闭。

但它也有代价:每新增一个产品,就要新增一个产品类和一个工厂类。如果产品很多,类数量会明显变多。

抽象工厂

工厂方法解决的是"同一类产品"的创建,比如只生产咖啡。

抽象工厂解决的是"一个产品族"的创建。产品族可以理解为一组应该一起使用的产品。

比如咖啡店不仅卖咖啡,还卖甜点:

风味产品族 咖啡 甜点
意大利风味 拿铁咖啡 提拉米苏
美式风味 美式咖啡 抹茶慕斯

抽象工厂可以这样设计:

java 复制代码
public interface DessertFactory {
    Coffee createCoffee();
    Dessert createDessert();
}
java 复制代码
public class ItalyDessertFactory implements DessertFactory {
    public Coffee createCoffee() {
        return new LatteCoffee();
    }

    public Dessert createDessert() {
        return new Tiramisu();
    }
}

#mermaid-svg-HM8nr22YUyDEx9JJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HM8nr22YUyDEx9JJ .error-icon{fill:#552222;}#mermaid-svg-HM8nr22YUyDEx9JJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HM8nr22YUyDEx9JJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HM8nr22YUyDEx9JJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HM8nr22YUyDEx9JJ .marker.cross{stroke:#333333;}#mermaid-svg-HM8nr22YUyDEx9JJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HM8nr22YUyDEx9JJ p{margin:0;}#mermaid-svg-HM8nr22YUyDEx9JJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HM8nr22YUyDEx9JJ .cluster-label text{fill:#333;}#mermaid-svg-HM8nr22YUyDEx9JJ .cluster-label span{color:#333;}#mermaid-svg-HM8nr22YUyDEx9JJ .cluster-label span p{background-color:transparent;}#mermaid-svg-HM8nr22YUyDEx9JJ .label text,#mermaid-svg-HM8nr22YUyDEx9JJ span{fill:#333;color:#333;}#mermaid-svg-HM8nr22YUyDEx9JJ .node rect,#mermaid-svg-HM8nr22YUyDEx9JJ .node circle,#mermaid-svg-HM8nr22YUyDEx9JJ .node ellipse,#mermaid-svg-HM8nr22YUyDEx9JJ .node polygon,#mermaid-svg-HM8nr22YUyDEx9JJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HM8nr22YUyDEx9JJ .rough-node .label text,#mermaid-svg-HM8nr22YUyDEx9JJ .node .label text,#mermaid-svg-HM8nr22YUyDEx9JJ .image-shape .label,#mermaid-svg-HM8nr22YUyDEx9JJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-HM8nr22YUyDEx9JJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HM8nr22YUyDEx9JJ .rough-node .label,#mermaid-svg-HM8nr22YUyDEx9JJ .node .label,#mermaid-svg-HM8nr22YUyDEx9JJ .image-shape .label,#mermaid-svg-HM8nr22YUyDEx9JJ .icon-shape .label{text-align:center;}#mermaid-svg-HM8nr22YUyDEx9JJ .node.clickable{cursor:pointer;}#mermaid-svg-HM8nr22YUyDEx9JJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HM8nr22YUyDEx9JJ .arrowheadPath{fill:#333333;}#mermaid-svg-HM8nr22YUyDEx9JJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HM8nr22YUyDEx9JJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HM8nr22YUyDEx9JJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HM8nr22YUyDEx9JJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HM8nr22YUyDEx9JJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HM8nr22YUyDEx9JJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HM8nr22YUyDEx9JJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HM8nr22YUyDEx9JJ .cluster text{fill:#333;}#mermaid-svg-HM8nr22YUyDEx9JJ .cluster span{color:#333;}#mermaid-svg-HM8nr22YUyDEx9JJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HM8nr22YUyDEx9JJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HM8nr22YUyDEx9JJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-HM8nr22YUyDEx9JJ .icon-shape,#mermaid-svg-HM8nr22YUyDEx9JJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HM8nr22YUyDEx9JJ .icon-shape p,#mermaid-svg-HM8nr22YUyDEx9JJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HM8nr22YUyDEx9JJ .icon-shape .label rect,#mermaid-svg-HM8nr22YUyDEx9JJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HM8nr22YUyDEx9JJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HM8nr22YUyDEx9JJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HM8nr22YUyDEx9JJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DessertFactory
ItalyDessertFactory
AmericanDessertFactory
LatteCoffee
Tiramisu
AmericanCoffee
MatchaMousse

抽象工厂的关键是保证产品族一致。你选择了意大利风味工厂,就会得到拿铁咖啡和提拉米苏,而不是拿铁咖啡配一个美式甜点。
#mermaid-svg-ddevK7tvW3MjNylD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ddevK7tvW3MjNylD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ddevK7tvW3MjNylD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ddevK7tvW3MjNylD .error-icon{fill:#552222;}#mermaid-svg-ddevK7tvW3MjNylD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ddevK7tvW3MjNylD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ddevK7tvW3MjNylD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ddevK7tvW3MjNylD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ddevK7tvW3MjNylD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ddevK7tvW3MjNylD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ddevK7tvW3MjNylD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ddevK7tvW3MjNylD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ddevK7tvW3MjNylD .marker.cross{stroke:#333333;}#mermaid-svg-ddevK7tvW3MjNylD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ddevK7tvW3MjNylD p{margin:0;}#mermaid-svg-ddevK7tvW3MjNylD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ddevK7tvW3MjNylD .cluster-label text{fill:#333;}#mermaid-svg-ddevK7tvW3MjNylD .cluster-label span{color:#333;}#mermaid-svg-ddevK7tvW3MjNylD .cluster-label span p{background-color:transparent;}#mermaid-svg-ddevK7tvW3MjNylD .label text,#mermaid-svg-ddevK7tvW3MjNylD span{fill:#333;color:#333;}#mermaid-svg-ddevK7tvW3MjNylD .node rect,#mermaid-svg-ddevK7tvW3MjNylD .node circle,#mermaid-svg-ddevK7tvW3MjNylD .node ellipse,#mermaid-svg-ddevK7tvW3MjNylD .node polygon,#mermaid-svg-ddevK7tvW3MjNylD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ddevK7tvW3MjNylD .rough-node .label text,#mermaid-svg-ddevK7tvW3MjNylD .node .label text,#mermaid-svg-ddevK7tvW3MjNylD .image-shape .label,#mermaid-svg-ddevK7tvW3MjNylD .icon-shape .label{text-anchor:middle;}#mermaid-svg-ddevK7tvW3MjNylD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ddevK7tvW3MjNylD .rough-node .label,#mermaid-svg-ddevK7tvW3MjNylD .node .label,#mermaid-svg-ddevK7tvW3MjNylD .image-shape .label,#mermaid-svg-ddevK7tvW3MjNylD .icon-shape .label{text-align:center;}#mermaid-svg-ddevK7tvW3MjNylD .node.clickable{cursor:pointer;}#mermaid-svg-ddevK7tvW3MjNylD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ddevK7tvW3MjNylD .arrowheadPath{fill:#333333;}#mermaid-svg-ddevK7tvW3MjNylD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ddevK7tvW3MjNylD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ddevK7tvW3MjNylD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ddevK7tvW3MjNylD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ddevK7tvW3MjNylD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ddevK7tvW3MjNylD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ddevK7tvW3MjNylD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ddevK7tvW3MjNylD .cluster text{fill:#333;}#mermaid-svg-ddevK7tvW3MjNylD .cluster span{color:#333;}#mermaid-svg-ddevK7tvW3MjNylD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ddevK7tvW3MjNylD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ddevK7tvW3MjNylD rect.text{fill:none;stroke-width:0;}#mermaid-svg-ddevK7tvW3MjNylD .icon-shape,#mermaid-svg-ddevK7tvW3MjNylD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ddevK7tvW3MjNylD .icon-shape p,#mermaid-svg-ddevK7tvW3MjNylD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ddevK7tvW3MjNylD .icon-shape .label rect,#mermaid-svg-ddevK7tvW3MjNylD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ddevK7tvW3MjNylD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ddevK7tvW3MjNylD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ddevK7tvW3MjNylD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 选择一个产品族工厂
创建同一风格咖啡
创建同一风格甜点
客户端拿到一组能配合使用的对象

三种工厂怎么选

模式 适合场景 主要问题
简单工厂 产品少,变化少 新增产品要改工厂
工厂方法 单一产品等级,经常新增产品 类数量增加
抽象工厂 多个产品等级组成产品族 新增产品等级很麻烦

这里的"产品等级"和"产品族"要分清:

概念 例子
产品等级 咖啡、甜点、手机、电脑
产品族 意大利风味、美式风味、华为、小米

如果只是新增一个咖啡类型,工厂方法更合适。

如果要保证"同一个品牌或风味的一组产品一起创建",抽象工厂更合适。

项目里怎么回答

面试问"你项目里用过工厂模式吗",不要只说"用过"。可以结合业务说:

我们在多类型对象创建场景里用过工厂模式。比如不同登录方式、不同支付渠道、不同消息发送渠道,它们都有统一接口,但具体实现不一样。如果直接在业务方法里写大量 if-else,新增一种类型就要改核心流程。后来把对象创建放到工厂里,业务层只根据类型拿到对应处理器,再执行统一方法。简单工厂适合类型少的场景;如果类型经常扩展,会进一步结合 Spring 容器,把每个实现注册成 Bean,再由工厂按类型获取。

小结

工厂模式的重点不是写一个类叫 Factory,而是把对象创建从业务流程里拆出来。

可以这样记:

简单工厂集中创建对象,工厂方法把每个产品的创建交给独立工厂,抽象工厂创建一整组能配合使用的产品族。

真正写代码时,别为了模式而模式。对象类型少、变化少,用简单工厂就够;扩展频繁,再升级成工厂方法或结合 Spring 管理。

相关推荐
不会写DN1 小时前
通过php 中的Route:: 的写法了解什么是静态类调用
android·java·php
小刘|1 小时前
SpringAIAlibaba快速接入阿里云百炼
java·spring boot·spring·maven
我命由我123451 小时前
由 ImageView 获取到的 Drawable 对象,它的 intrinsicWidth、intrinsicWidth 与实际图片的尺寸
java·开发语言·java-ee·android studio·android jetpack·android-studio·android runtime
xuankuxiaoyao1 小时前
Axios-图书列表案例
开发语言·前端·javascript
Han.miracle1 小时前
Jackson 工具类详解:ObjectMapper 配置、泛型擦除、TypeReference 与 JavaType
java·spring boot·spring
guslegend1 小时前
Java 创建对象有几种方式
java·开发语言
暗暗别做白日梦1 小时前
延时消息的几种实现方式及优缺点
java
带娃的IT创业者1 小时前
深度解析 Bun:重新定义 JavaScript 运行时的性能边界
开发语言·javascript·node.js·ecmascript·bun·运行时
极客先躯1 小时前
高级java每日一道面试题-2026年02月08日-实战篇[Docker]-如何实现容器的快照和恢复?
java·运维·docker·容器·备份·持久化·恢复