浅析Java设计模式之四策略模式


title: 浅析Java设计模式之四策略模式

date: 2018-12-29 17:26:17
categories: 设计模式
description: 浅析Java设计模式之四策略模式

1. 目录

  • [1. 目录](#1. 目录)
  • [2. 概念](#2. 概念)
    • [2.1. 应用场景](#2.1. 应用场景)
    • [2.2. 优缺点](#2.2. 优缺点)
      • [2.2.1. 优点](#2.2.1. 优点)
      • [2.2.2. 缺点](#2.2.2. 缺点)
  • [3. 模式结构](#3. 模式结构)
  • [4. 样例](#4. 样例)
    • [4.1. 定义策略](#4.1. 定义策略)
    • [4.2. 定义具体策略](#4.2. 定义具体策略)
    • [4.3. 定义上下文](#4.3. 定义上下文)
    • [4.4. 实现效果](#4.4. 实现效果)
  • [5. 拓展](#5. 拓展)

2. 概念

策略模式是我们 Java 开发中最最基础的开发模式,我们在日常生活中都可以找到与之相关。现实中我们各种为实现某种目标而选择的具体某种行为,都可以归纳为之策略。

我们选择去旅行,对于交通工具的选择上,我们有飞机、客车、高铁、自驾等做种选择,每一种选择都代表一种策略,都为了我们去旅行这个目标而服务。

而在软件开发中我们也常遇到类似的情况,当为实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。

所以这里给策略( Strategy )模式下个定义,模式定义一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

总之,所以在本质上策略的设计模式属于行为型模式一种,通过定义的一套算法类,进行封装,让算法类之间可以相互替换,从而达到一种按照调用侧/实现侧去决定目标实现。策略模式可以最大程度的避免代码中 if else 以及 switch 语句。

2.1. 应用场景

  • 在需要多实现场景下,但只在算法或行为上略有差异
  • 在算法或行为上须自由完成切换
  • 需要解脱或者屏蔽多条件判断的场景

2.2. 优缺点

2.2.1. 优点

  • 算法或行为可自由切换
  • 避免在实现过程中,使用多重条件判断
  • 实现结构上具备扩展性良好和可读性

2.2.2. 缺点

  • 策略的基础条件随着业务增长会增多,可能存在臃肿
  • 不是很安全,因为所有的策略条件都对外暴露

3. 模式结构

策略模式 的实现包含三个组成部分,分别为 策略类具体策略类上下文

  • Strategy:策略类,用于定义所有支持算法的公共接口;
  • ConcreteStrategy:是具体策略类,封装了具体的算法或行为,继承于 Strategy
  • Context:是上下文,用一个 ConcreteStrategy 来配置,维护一个对 Strategy 对象的引用

4. 样例

此处假定我们在商场购物,选购的商品为 桌面电脑,那么在用户支付的环节,对支付的手段,可以有多种选择,例如 现金信用卡积分 等。那么我们在设计过程中,就遵循这种这种实现。

4.1. 定义策略

抽象一个付款方式,我们没有指明具体是哪一种付款方式,留给实现类去具体说明。

java 复制代码
public interface Payment {

    void payment();
}

4.2. 定义具体策略

  • 现金
java 复制代码
public class Cash implements Payment{

    @Override
    public void payment() {
        System.out.println("现金付款");
    }
}
  • 信用卡
java 复制代码
public class Credit implements Payment{

    @Override
    public void payment() {
        System.out.println("信用卡付款");
    }
}
  • 积分
java 复制代码
public class Points implements Payment{

    @Override
    public void payment() {
        System.out.println("积分付款");
    }
}

4.3. 定义上下文

java 复制代码
public class Shopping {

    private Payment payment;

    public Shopping(Payment payment) {
        this.payment = payment;
    }

    public void buyDesktop(){
        System.out.println("购买台式机");
        payment.payment();
    }

}

4.4. 实现效果

java 复制代码
@DisplayName("策略应用")
@Test
public void testStrategy() {
    Payment payment = new Cash();
    Shopping shopping = new Shopping(payment);
    shopping.buyDesktop();
}

5. 拓展

在我们上面使用 策略模式 的设计中,如果当存在的具体策略很多时,策略的客户端在管理所有策略将变得很臃肿且复杂,那如果在环境类中使用一个策略工厂模式来管理具体策略类,那么将大大减少客户端的工作复杂度。

java 复制代码
package io.github.rothschil.design.strategy.factory;

import cn.hutool.core.util.ClassUtil;
import io.github.rothschil.design.strategy.Payment;
import io.github.rothschil.design.strategy.StrategyEnum;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class StrategyFactory {

    private static Map<String, Payment> PAYMENT_MAP = new HashMap<>();

    public StrategyFactory() {

        // 反射出子类
        Set<Class<?>> sets = ClassUtil.scanPackageBySuper("io.github.rothschil", Payment.class);
        for (Class<?> it : sets) {
            try {
                Payment payment = (Payment)it.newInstance();
                PAYMENT_MAP.put(it.getSimpleName(), payment);
            } catch (InstantiationException | IllegalAccessException ignored) {

            }
        }
    }

    public Payment get(StrategyEnum keyEnum) {
        return PAYMENT_MAP.get(keyEnum.getKey());
    }

}

那我们对我们上面的测试类也进行改造下,

java 复制代码
    @DisplayName("策略应用")
    @Test
    public void testStrategy2() {
        StrategyFactory strategyFactory = new StrategyFactory();
        Payment payment = strategyFactory.get(StrategyEnum.CASH);
        Shopping shopping = new Shopping(payment);
        shopping.buyDesktop();
    }
相关推荐
LucianaiB几秒前
如何做好一份优秀的技术文档:专业指南与最佳实践
android·java·数据库
面朝大海,春不暖,花不开24 分钟前
自定义Spring Boot Starter的全面指南
java·spring boot·后端
得过且过的勇者y25 分钟前
Java安全点safepoint
java
夜晚回家1 小时前
「Java基本语法」代码格式与注释规范
java·开发语言
斯普信云原生组1 小时前
Docker构建自定义的镜像
java·spring cloud·docker
wangjinjin1801 小时前
使用 IntelliJ IDEA 安装通义灵码(TONGYI Lingma)插件,进行后端 Java Spring Boot 项目的用户用例生成及常见问题处理
java·spring boot·intellij-idea
wtg44521 小时前
使用 Rest-Assured 和 TestNG 进行购物车功能的 API 自动化测试
java
白宇横流学长2 小时前
基于SpringBoot实现的大创管理系统设计与实现【源码+文档】
java·spring boot·后端
fat house cat_2 小时前
【redis】线程IO模型
java·redis
stein_java3 小时前
springMVC-10验证及国际化
java·spring