浅析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();
    }
相关推荐
武子康7 分钟前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs
武子康9 分钟前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql
苏-言15 分钟前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
界面开发小八哥22 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
草莓base36 分钟前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
Allen Bright1 小时前
maven概述
java·maven
编程重生之路1 小时前
Springboot启动异常 错误: 找不到或无法加载主类 xxx.Application异常
java·spring boot·后端
薯条不要番茄酱1 小时前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
努力进修1 小时前
“探索Java List的无限可能:从基础到高级应用“
java·开发语言·list
politeboy1 小时前
k8s启动springboot容器的时候,显示找不到application.yml文件
java·spring boot·kubernetes