龙空技术网

Java设计模式之策略模式(应用场景、示例)

程序员的秃头之路 196

前言:

当前看官们对“java 状态模式和策略模式”大体比较讲究,我们都想要学习一些“java 状态模式和策略模式”的相关内容。那么小编在网上搜集了一些有关“java 状态模式和策略模式””的相关知识,希望兄弟们能喜欢,咱们一起来了解一下吧!

什么是策略模式?

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一组同类型的算法,在不同的类中封装起来,每种算法可以根据当前场景相互替换,从而使算法的变化独立于使用它们的客户端(即算法的调用者)。策略模式可以让算法的选择与使用分离,提高了代码的灵活性和可维护性。

在策略模式中,有三个核心角色:

1、 环境类(Context):它持有一个策略对象的引用,可以通过策略对象执行具体的算法。 2、 抽象策略类(Strategy):它定义了一个公共接口,用于所有具体策略类的统一调用。 3、 具体策略类(Concrete Strategy):它实现了抽象策略类定义的接口,提供具体的算法实现。

应用场景

1、 当有多个类似的算法,且客户端需要根据不同的情况选择使用不同的算法时,可以使用策略模式。它将算法的选择与使用分离,提高了代码的灵活性和可维护性。

2、 当一个类中有多个条件判断语句,并且每个条件执行不同的操作时,可以考虑使用策略模式。它可以避免大量的条件语句,使得代码更加清晰、可读性更高。

3、 当需要在运行时动态地切换算法时,策略模式可以提供一种简洁的方式。通过修改环境类持有的策略对象,可以在不影响客户端代码的情况下切换算法。

总的来说,策略模式可以帮助实现算法的封装和选择,提高代码的可维护性、可扩展性和可读性。

示例

实现用户购物下单场景

首先,我们定义一个抽象策略接口 DiscountStrategy

// 抽象策略接口public interface DiscountStrategy {    double calculateDiscount(double amount);}

然后,我们实现具体的策略类,比如会员折扣策略和新用户折扣策略:

// 具体策略类 - 会员折扣public class MemberDiscountStrategy implements DiscountStrategy {    @Override    public double calculateDiscount(double amount) {        // 假设会员折扣为 10%        return amount * 0.1;    }}// 具体策略类 - 新用户折扣public class NewUserDiscountStrategy implements DiscountStrategy {    @Override    public double calculateDiscount(double amount) {        // 假设新用户折扣为 20 元        return 20;    }}

接下来,我们创建购物车类 ShoppingCart,它持有一个策略对象,并提供购物和生成订单的方法:

// 环境类 - 购物车public class ShoppingCart {    private DiscountStrategy discountStrategy;    private List<Item> items;    public ShoppingCart(DiscountStrategy discountStrategy) {        this.discountStrategy = discountStrategy;        this.items = new ArrayList<>();    }    public void addItem(Item item) {        items.add(item);    }    public double calculateTotalAmount() {        double totalAmount = 0;        for (Item item : items) {            totalAmount += item.getPrice();        }        return totalAmount;    }    public double calculateDiscountAmount() {        double totalAmount = calculateTotalAmount();        return discountStrategy.calculateDiscount(totalAmount);    }    public void generateOrder() {        double totalAmount = calculateTotalAmount();        double discountAmount = calculateDiscountAmount();        double finalAmount = totalAmount - discountAmount;        // 生成订单的逻辑        // ...        System.out.println(totalAmount);        System.out.println(discountAmount);        System.out.println(finalAmount);    }      @AllArgsConstructor    @NoArgsConstructor    @Data    public static class Item {        private String goodsName;        private double price;    }}

最后,我们可以使用这些类进行示例测试:

public class Main {    public static void main(String[] args) {        // 创建购物车并设置会员折扣策略        DiscountStrategy memberDiscountStrategy = new MemberDiscountStrategy();        ShoppingCart cart = new ShoppingCart(memberDiscountStrategy);        // 添加商品到购物车        Item item1 = new Item("iPhone", 999);        Item item2 = new Item("Headphones", 99);        cart.addItem(item1);        cart.addItem(item2);        // 生成订单        cart.generateOrder();    }}

这个示例演示了使用策略模式来处理用户购物下单场景。根据不同的折扣策略,购物车可以计算总金额并生成相应的订单。你可以根据实际需求定义更多的具体策略类,并在购物车中切换不同的策略来实现不同的折扣计算逻辑。

策略模式与函数式编程结合示例

当结合策略模式与函数式编程的思想时,可以使用 Map(映射)来存储不同策略的函数,并根据需要选择执行的函数。下面是一个示例,展示了策略模式与函数式编程的结合:

import java.util.HashMap;import java.util.Map;import java.util.function.Function;public class Main {    public static void main(String[] args) {        // 使用Map存储不同策略的函数        Map<String, Function<Void, Void>> strategyMap = new HashMap<>();        strategyMap.put("A", v -> {            new StrategyA().execute();            return null;        });        strategyMap.put("B", v -> {            new StrategyB().execute();            return null;        });        // 根据需要选择执行的函数        String strategyKey = "A";        Function<Void, Void> strategyFunction = strategyMap.get(strategyKey);        if (strategyFunction != null) {            strategyFunction.apply(null);        }    }}// 抽象策略接口interface Strategy {    void execute();}// 具体策略类 - 策略Aclass StrategyA implements Strategy {    @Override    public void execute() {        System.out.println("执行策略A");    }}// 具体策略类 - 策略Bclass StrategyB implements Strategy {    @Override    public void execute() {        System.out.println("执行策略B");    }}

在上述示例中,我们定义了一个抽象策略接口 Strategy 和两个具体策略类 StrategyAStrategyB。然后,我们使用 Map 存储不同策略的函数,键是策略的标识符,值是执行策略的函数。在示例中,我们使用了 Java 8 中的函数式接口 Function,该接口接受一个输入并返回一个输出。

main 方法中,我们选择了策略标识符为 "A" 的策略,并从 strategyMap 中获取对应的函数。如果找到了函数,我们就调用该函数来执行策略。这样,我们通过将策略与函数的映射存储在 Map 中,实现了策略模式与函数式编程的结合。

请注意,上述示例只是简单展示了策略模式与函数式编程的结合方式。在实际应用中,你可以根据需求扩展和定制更多的策略,并结合函数式编程的特性,使代码更加简洁和灵活。

注意事项

在使用策略模式时,有几个注意事项需要考虑:

1、 接口设计:确保抽象策略接口(或抽象基类)定义了所有具体策略类需要实现的方法,以确保策略对象的一致性。良好的接口设计可以提高代码的可扩展性和可维护性。

2、 策略切换:策略模式的核心是在运行时动态地切换策略对象。因此,确保在环境类中提供了切换策略的方法,使得客户端能够方便地更改策略。

3、 策略数量:在设计时需要仔细考虑策略的数量。如果策略过多,可能会导致类爆炸问题,增加代码复杂性。合理地组织和分类策略,避免策略类过于庞大和混乱。

4、 策略选择:在选择具体策略时,需要根据实际需求和场景进行权衡和选择。不同的策略可能有不同的性能、复杂度和效果,需要选择最适合的策略。

5、 策略耦合:策略模式将策略对象与环境类解耦,但策略对象之间可能存在一定的耦合关系。在实现具体策略时,需要注意避免策略之间的紧耦合,以保持策略的独立性和可替换性。

6、 策略和状态:策略模式与状态模式有一些相似之处,因为它们都涉及到在运行时选择不同的行为。但策略模式更侧重于算法的选择和封装,而状态模式更侧重于对象状态的管理和转换。因此,在使用策略模式时,需要明确区分策略和状态的概念。

综上所述,注意上述事项可以帮助你正确地应用策略模式,以实现灵活、可维护和可扩展的代码结构。

策略模式的缺点客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。策略类会增多,如果备选的策略很多的话,那么对象的数目就会很可观。这会增加系统的复杂性和维护成本。所有策略类都需要对外暴露,这可能会暴露一些内部的实现细节或者影响算法的安全性。

标签: #java 状态模式和策略模式