一、策略模式(Strategy Pattern):算法的灵活切换

(一)策略模式的核心概念

想象你正坐镇“代码指挥中心”,面对瞬息万变的战场形势(运行时复杂状况),需要随时切换作战“策略”(算法),同时保证“指挥系统”(客户端代码)稳如泰山。这时,策略模式(Strategy Pattern) 便如同天降奇兵。

作为行为型设计模式(Behavioral Pattern)的代表,策略模式将各类算法封装进独立的“策略类”中,藏于代码宝库,按需调用。无论战况如何变化,只需更换“策略锦囊”即可应对,严格遵守“开闭原则”(Open-Closed Principle),扩展轻松,修改无忧。

策略模式的结构如下表所示:

组件描述示例图示示意
抽象策略类定义通用策略行为接口,是具体策略类遵循的“模板”,规定核心方法。PromotionStrategy 接口,定义 applyPromotion 方法。[长方形框代表抽象策略类,内部标注方法名]
具体策略类实现抽象策略类,承载独特算法逻辑,各显神通。FullReductionStrategy(满减)、DiscountStrategy(折扣)。[多个小长方形框代表具体策略类,指向抽象策略类,标注各自算法]
上下文类持有策略类引用,按场景调用方法,像“指挥官”调配策略。ShoppingCart,依据总价调用策略计算最终价格。[圆形框代表上下文类,箭头指向抽象策略类,体现关联]

(二)生活实例:披萨店的“创意大厨”

走进一家个性化披萨店,点一份培根披萨。老板不提供成品,而是给你食材和制作指南,让你自由发挥。多放芝士、精准控火、妙调佐料,这些“操作”即为“策略”。你(客户端)依据口味挑选策略制作披萨,正如策略模式中,客户端根据实际情况灵活调用策略类,以达到个性化目的。

(三)代码实战:电商促销场景

在竞争白热化的电商“战场”,促销策略是核心武器。以下使用 Java 代码构建一个“促销策略库”,展示策略模式的应用。

// 抽象策略接口,定义促销通用规则
interface PromotionStrategy {
    double applyPromotion(double totalPrice);
}

// 具体策略:满减策略,达门槛即减钱
class FullReductionStrategy implements PromotionStrategy {
    private double fullAmount;
    private double reductionAmount;

    public FullReductionStrategy(double fullAmount, double reductionAmount) {
        this.fullAmount = fullAmount;
        this.reductionAmount = reductionAmount;
    }

    @Override
    public double applyPromotion(double totalPrice) {
        if (totalPrice >= fullAmount) {
            return totalPrice - reductionAmount;
        } else {
            return totalPrice;
        }
    }
}

// 具体策略:折扣策略,按折扣率计算
class DiscountStrategy implements PromotionStrategy {
    private double discountRate;

    public DiscountStrategy(double discountRate) {
        this.discountRate = discountRate;
    }

    @Override
    public double applyPromotion(double totalPrice) {
        return totalPrice * discountRate;
    }
}

// 上下文类,持有策略引用并调度
class ShoppingCart {
    private PromotionStrategy promotionStrategy;
    private double totalPrice;

    public ShoppingCart(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }

    public void addItem(double price) {
        totalPrice += price;
    }

    public double calculateFinalPrice() {
        return promotionStrategy.applyPromotion(totalPrice);
    }
}

// 测试代码,验证策略威力
public class StrategyPatternDemo {
    public static void main(String[] args) {
        // 场景一:满减策略,满 200 减 50
        PromotionStrategy fullReduction = new FullReductionStrategy(200, 50);
        ShoppingCart cart1 = new ShoppingCart(fullReduction);
        cart1.addItem(100);
        cart1.addItem(100);
        System.out.println("满减策略下最终价格:" + cart1.calculateFinalPrice());

        // 场景二:折扣策略,打 8 折
        PromotionStrategy discount = new DiscountStrategy(0.8);
        ShoppingCart cart2 = new ShoppingCart(discount);
        cart2.addItem(150);
        cart2.addItem(50);
        System.out.println("折扣策略下最终价格:" + cart2.calculateFinalPrice());
    }
}

在此架构中,PromotionStrategy 接口如同“魔法法典”,规范促销规则;FullReductionStrategyDiscountStrategy 像“魔法师”执行具体优惠计算;ShoppingCart 则是“指挥官”,依据策略计算花费。若需更换策略,仅需修改传入对象,主代码无需变动。

(四)策略模式的优势

  1. 扩展性强:若电商想增加“积分抵现金”策略,只需编写一个实现接口的新类,现有代码结构稳固。
  2. 切换灵活:支持运行时动态切换策略。无论是购物节还是新品首发,客户端代码均可从容应对业务变化。

二、工厂模式(Factory Pattern):对象的创建工坊

(一)工厂模式的核心概念

在软件设计的另一角,工厂模式(Factory Pattern) 扎根于创建型设计模式(Creational Pattern)。它像一座“神奇工坊”:你(客户端)递交“订单”(创建对象请求),“工匠”(工厂类)按“秘方”(预设逻辑)制造“珍宝”(对象),隐藏复杂过程。客户端只需直接使用对象,无需关心创建细节,从而显著提升易用性与可维护性。

工厂模式的结构如下表所示:

组件描述示例图示示意
抽象产品类定义产品通用行为属性,作具体产品“模板”。Shape 接口,draw 方法定义绘制规范。[长方形框代表抽象产品类,内部写方法]
具体产品类实现抽象产品类,具实际功能特性。Circle(圆)、Rectangle(矩形)。[多个小框代表具体产品类,指向抽象产品类]
抽象工厂类定义创建产品的抽象方法,把控流程“大方向”。ShapeFactory 接口,createShape 方法定规则。[大圆形框代表抽象工厂类,写方法]
具体工厂类实现抽象工厂类,按逻辑造具体产品。CircleFactoryRectangleFactory[小圆形框代表具体工厂类,指向抽象工厂与对应产品]

(二)生活对照:传统披萨店的“高效出餐”

在传统披萨店点一份培根披萨,坐下等待即可。后厨如同“披萨工厂”,师傅依流程配料、烘焙,很快美味上桌。你(客户端)不管制作过程,只享美味。这就是工厂模式的日常体现。

(三)代码落地:图形绘制场景

在图形绘制软件中,利用工厂模式管理图形创建,代码如下:

// 抽象产品接口,定义图形绘制规范
interface Shape {
    void draw();
}

// 具体产品:圆形
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}

// 具体产品:矩形
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}

// 抽象工厂接口,定义生产规矩
interface ShapeFactory {
    Shape createShape();
}

// 具体工厂:圆形工厂
class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}

// 具体工厂:矩形工厂
class RectangleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Rectangle();
    }
}

// 测试代码,验证工厂产出
public class FactoryPatternDemo {
    public static void main(String[] args) {
        // 生产圆形
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.createShape();
        circle.draw();

        // 生产矩形
        ShapeFactory rectangleFactory = new RectangleFactory();
        Shape rectangle = rectangleFactory.createShape();
        rectangle.draw();
    }
}

在此“艺术工坊”中,Shape 接口如“绘画宝典”,CircleRectangle 展现独特画风,ShapeFactory 控制流程。客户端通过工厂获取图形,无需关心细节,实现彻底解耦。若需增加“三角形”,只需按套路扩展代码,现有逻辑不受影响。

(四)工厂模式的优势

  1. 创建与使用分离:客户端在前台使用对象,工厂在后台创建。后台修改创建逻辑(“装修”),前台无需变动,系统稳定性高。
  2. 创建逻辑统一:创建规则、资源调配集中在工厂类中,优化参数或逻辑时只需内部微调,管理清晰高效。

三、终极对决:策略模式 vs 工厂模式

为了更清晰地区分二者,以下从多个维度进行对比:

对比维度策略模式(Strategy Pattern)工厂模式(Factory Pattern)
设计初衷聚焦算法的灵活切换与封装,应对业务规则多变,让系统低成本适应变化。着眼对象创建的便利性,隔离复杂创建过程,提升系统易用性与可维护性。
角色职责策略类实现算法,上下文类调度策略。策略类精研算法,上下文类负责调配。工厂类把控创建,产品类展示功能。工厂类负责生产,产品类待发挥功能。
应用场景算法频繁切换处,如金融产品利息计算(活期、定期等切换)、支付渠道选择。对象创建复杂需管理处,如游戏角色创建(不同种族、职业)、数据库连接获取。

总结

看完这场“巅峰对决”,相信大家对策略模式和工厂模式已有了清晰的认识。在实际项目中,切勿“乱点鸳鸯谱”,应根据实际需求按需“配对”:

  • 若需动态切换算法,请选择策略模式
  • 若需屏蔽创建细节,请选择工厂模式

合理运用设计模式,能让代码“战斗力”飙升,助你成为优秀的软件架构师。

说明:本文基于标准 Java SE 环境编写,设计模式为核心软件工程理论,适用于大多数面向对象编程语言及版本。