设计模式之策略模式

简介: 设计模式之策略模式

策略模式

完整代码地址 https://gitee.com/zyxscuec/Design-pattern.git

(1)概念

策略模式(Strategy Pattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。

(2)策略模式的应用场景

1、假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。

2、一个系统需要动态地在几种算法中选择一种。

(3)用策略模式实现选择支付方式的业务场景

大家都知道,很多电商平台经常会有优惠活动,优惠策略会有很多种可能如:领取优惠券抵扣、返现促销、拼团优惠。下面我们用代码来模拟。

整体的类图

首先我们创建一个促销策略的抽象 PromotionStrategy:

package com.alibaba.design.strategypattern.promotion;
/**
 * 促销策略抽象
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:01
 */
public interface PromotionStrategy {
    public void doPromotion();
}

然后分别创建优惠券抵扣策略 CouponStrategy 类、返现促销策略 CashbackStrategy类、拼团优惠策略 GroupbuyStrategy 类和无优惠策略 EmptyStrategy 类:

  • CashbackStrategy类(返现促销)
package com.alibaba.design.strategypattern.promotion;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:03
 */
public class CashbackStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("通过返现促销,消费额到达一定的额度后可以直接返现");
    }
}
  • CouponStrategy类(优惠券促销)
package com.alibaba.design.strategypattern.promotion;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:03
 */
public class CouponStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("通过优惠券的形式来促销");
    }
}
  • EmptyStrategy类(无促销)
package com.alibaba.design.strategypattern.promotion;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:05
 */
public class EmptyStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("无促销活动");
    }
}
  • GroupbuyStrategy类(组团促销)
package com.alibaba.design.strategypattern.promotion;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:05
 */
public class GroupbuyStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("通过拼团促销");
    }
}

然后创建促销活动方案 PromotionActivity 类

package com.alibaba.design.strategypattern.promotion;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:06
 */
public class PromotionActivity {
    private PromotionStrategy promotionStrategy;
    public PromotionActivity(PromotionStrategy promotionStrategy){
        this.promotionStrategy = promotionStrategy;
    }
    public void execute(){
        promotionStrategy.doPromotion();
    }
}

编写客户端测试类PromotionActivityTest

package com.alibaba.design.strategypattern.test;
import com.alibaba.design.strategypattern.promotion.CashbackStrategy;
import com.alibaba.design.strategypattern.promotion.CouponStrategy;
import com.alibaba.design.strategypattern.promotion.PromotionActivity;
import com.alibaba.design.strategypattern.promotion.PromotionStrategyFactory;
import org.apache.commons.lang3.StringUtils;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:23
 */
public class PromotionActivityTest {
    public static void main(String[] args) {
        System.out.println("============No.1===========");
        PromotionActivityTest.testPromotionActivity1();
        System.out.println("============No.2===========");
        PromotionActivityTest.testPromotionActivity2();
        System.out.println("============No.3===========");
        PromotionActivityTest.testPromotionActivity3();
    }
    public static void testPromotionActivity1(){
        PromotionActivity activity618 = new PromotionActivity(new CouponStrategy());
        PromotionActivity activity1111 = new PromotionActivity(new CashbackStrategy());
        activity618.execute();
        activity1111.execute();
    }
    public static void testPromotionActivity2() {
        PromotionActivity promotionActivity = null;
        String promotionKey = "COUPON";
        if (StringUtils.equals(promotionKey, "COUPON")) {
            promotionActivity = new PromotionActivity(new CouponStrategy());
        } else if (StringUtils.equals(promotionKey, "CASHBACK")) {
            promotionActivity = new PromotionActivity(new CashbackStrategy());
        }
        promotionActivity.execute();
    }
    public static void testPromotionActivity3() {
        String promotionKey = "GROUPBUY";
        PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
        promotionActivity.execute();
    }
}

testPromotionActivity1()方法测试代码放到实际的业务场景其实并不实用,不能让客户自己选择不同的策略支付,而是由商家指定的方式,这样很不友好。

testPromotionActivity2()方法这样改造之后,满足了业务需求,客户可根据自己的需求选择不同的优惠策略了。不过经过一段时间的业务积累,我们的促销活动会越来越多代码将会需要更多判断逻辑可能也变得越来越复杂。这时候,我们是不需要思考代码是不是应该重构了?结合之前的单例模式和工厂模式,创建

PromotionStrategyFactory类

package com.alibaba.design.strategypattern.promotion;
import java.util.HashMap;
import java.util.Map;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-11:37
 */
public class PromotionStrategyFactory {
    private static Map<String,PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<String, PromotionStrategy>();
    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.COUPON,new CouponStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK,new CashbackStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY,new GroupbuyStrategy());
    }
    private static final PromotionStrategy NON_PROMOTION = new EmptyStrategy();
    private PromotionStrategyFactory(){}
    public static PromotionStrategy getPromotionStrategy(String promotionKey){
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }
    private interface PromotionKey{
        String COUPON = "COUPON";
        String CASHBACK = "CASHBACK";
        String GROUPBUY = "GROUPBUY";
    }
}

代码优化之后,创建testPromotionActivity3()方法,每次上新活动,不影响原来的代码逻辑。

策略模式在 JDK 源码中的体现

首先来看一个比较常用的比较器 Comparator 接口,我们看到的一个大家常用的compare()方法,就是一个策略抽象实现:

最终根据什么去排序是由用户自己定义的。

比如,我们定义一个User类,里面包含姓名和分数两个属性

package com.alibaba.design.strategypattern.test;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-17:05
 */
public class User {
    public String name;
    public int score;
    public User(String name, int score) {
        this.name =name;
        this.score = score;
    }
}

那么我们重写的compare方法如果是比较的分数的话,最终将会是按照分数进行排序

package com.alibaba.design.strategypattern.test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-17:02
 */
public class UserTest implements Comparator<User> {
    @Override
    public int compare(User o1, User o2) {
        return o1.score-o2.score;
    }
    public static void main(String[] args) {
        ArrayList<User> list = new ArrayList<>();
        list.add(new User("Tom",98));
        list.add(new User("Jerry",95));
        list.add(new User("Jane",99));
        list.add(new User("Mary",100));
        Collections.sort(list, new UserTest());
        for(User index:list) {
            System.out.println(" score: " + index.score + " name : " + index.name);
        }
    }
}

也可以按照name的首字母进行排序

package com.alibaba.design.strategypattern.test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-17:02
 */
public class UserTest implements Comparator<User> {
    @Override
    public int compare(User u1, User u2) {
        return u1.name.compareTo(u2.name);
    }
    public static void main(String[] args) {
        ArrayList<User> list = new ArrayList<>();
        list.add(new User("Tom",98));
        list.add(new User("Jerry",95));
        list.add(new User("Jane",99));
        list.add(new User("Mary",100));
        Collections.sort(list, new UserTest());
        for(User index:list) {
            System.out.println(" score: " + index.score + " name : " + index.name);
        }
    }
}

这就是策略模式在JDK中的应用之一。

还有一个非常典型的场景,Spring 的初始化也采用了策略模式,不同的类型的类采用不

同的初始化策略。首先有一个 InstantiationStrategy 接口,我们来看一下源码

package org.springframework.beans.factory.support;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.lang.Nullable;
public interface InstantiationStrategy {
    Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3) throws BeansException;
    Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3,
    Constructor<?> var4, @Nullable Object... var5) throws BeansException;
    Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3, @Nullable
    Object var4, Method var5, @Nullable Object... var6) throws BeansException;
}

顶层的策略抽象非常简单,但是它下面有两种策略 SimpleInstantiationStrategy 和

CglibSubclassingInstantiationStrategy,我们看一下类图:

打开类图我们还发现 CglibSubclassingInstantiationStrategy 策略类还继承了SimpleInstantiationStrategy 类,说明在实际应用中多种策略之间还可以继承使用。我们可以作为一个参考,在实际业务场景中,可以根据需要来设计。

(4) 策略模式的优缺点

  • 优点:
    1、策略模式符合开闭原则。
    2、避免使用多重条件转移语句,如 if…else…语句、switch 语句
    3、使用策略模式可以提高算法的保密性和安全性。
  • 缺点:
    1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
    2、代码中会产生非常多策略类,增加维护难度。


相关文章
|
1月前
|
设计模式 算法 Kotlin
Kotlin - 改良设计模式 - 策略模式
Kotlin - 改良设计模式 - 策略模式
47 4
|
3月前
|
设计模式 算法 测试技术
PHP中的设计模式:策略模式的应用与实践
在软件开发的浩瀚海洋中,设计模式如同灯塔,指引着开发者们避开重复造轮子的暗礁,驶向高效、可维护的代码彼岸。今天,我们将聚焦于PHP领域中的一种重要设计模式——策略模式,探讨其原理、应用及最佳实践,揭示如何通过策略模式赋予PHP应用灵活多变的业务逻辑处理能力,让代码之美在策略的变换中熠熠生辉。
|
22天前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
40 1
|
25天前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
29 2
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
45 2
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文通过游泳运动员的案例,介绍策略模式及其在Kotlin中的改良应用,利用高阶函数简化代码结构,提高灵活性。
38 3
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文介绍策略模式在Kotlin中的应用,通过游泳运动员的例子,展示如何使用接口和高阶函数实现策略模式,使代码更简洁、灵活。
34 2
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
66 3
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
31 3
|
2月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第9天】 策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在PHP开发中,通过使用策略模式,我们可以轻松切换算法或逻辑处理方式而无需修改现有代码结构。本文将深入探讨策略模式的定义、结构以及如何在PHP中实现该模式,并通过实际案例展示其应用价值和优势。
38 1