浅析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();
    }
相关推荐
xyliiiiiL15 分钟前
一文总结常见项目排查
java·服务器·数据库
shaoing17 分钟前
MySQL 错误 报错:Table ‘performance_schema.session_variables’ Doesn’t Exist
java·开发语言·数据库
腥臭腐朽的日子熠熠生辉1 小时前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
ejinxian1 小时前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
杉之1 小时前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
圈圈编码2 小时前
Spring Task 定时任务
java·前端·spring
俏布斯2 小时前
算法日常记录
java·算法·leetcode
27669582922 小时前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿
爱的叹息2 小时前
Java 连接 Redis 的驱动(Jedis、Lettuce、Redisson、Spring Data Redis)分类及对比
java·redis·spring
程序猿chen2 小时前
《JVM考古现场(十五):熵火燎原——从量子递归到热寂晶壁的代码涅槃》
java·jvm·git·后端·java-ee·区块链·量子计算