🖊策略模式学习笔记
时间:2019-11-07
本文章向大家介绍🖊策略模式学习笔记,主要包括🖊策略模式学习笔记使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、简介
策略模式(Strategy Pattern)指的是对象具备某个行为,但是在不同的场景中,该行为有不同的实现算法。比如一个人的交税比率与他的工资有关,不同的工资水平对应不同的税率。
策略模式 使用的就是面向对象的继承和多态机制,从而实现同一行为在不同场景下具备不同实现。
- 主要解决
在有多种算法相似的情况下,使用 if...else 或 switch...case 所带来的复杂性和臃肿性。
- 优点&缺点
优点
- 算法多样性,且具备自由切换功能;
- 有效避免多重条件判断,增强了封装性,简化了操作,降低出错概率;
- 扩展性良好,策略类遵顼 里氏替换原则,可以很方便地进行策略扩展;
缺点
- 策略类数量增多,且所有策略类都必须对外暴露,以便客户端能进行选择;
- 使用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
- 注意事项
如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
二、模式讲解
从 UML 类图中,我们可以看到,策略模式 主要包含三种角色:
- 上下文角色(Context):用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
- 抽象策略角色(Strategy):规定策略或算法的行为;
- 具体策略角色(ConcreteStrategy):具体的策略或算法实现;
以下是 策略模式 的通用代码:
class Client {
public static void main(String[] args) {
//选择一个具体策略
IStrategy strategy = new ConcreteStrategyA();
//来一个上下文环境
Context context = new Context(strategy);
//客户端直接让上下文环境执行算法
context.algorithm();
}
//抽象策略类 Strategy
interface IStrategy {
void algorithm();
}
//具体策略类 ConcreteStrategy
static class ConcreteStrategyA implements IStrategy {
@Override
public void algorithm() {
System.out.println("Strategy A");
}
}
//具体策略类 ConcreteStrategy
static class ConcreteStrategyB implements IStrategy {
@Override
public void algorithm() {
System.out.println("Strategy B");
}
}
//上下文环境
static class Context {
private IStrategy mStrategy;
public Context(IStrategy strategy) {
this.mStrategy = strategy;
}
public void algorithm() {
this.mStrategy.algorithm();
}
}
}
三、举个例子
例子:假设现在有两个数与一个运算符,要求使用该运算符操作这两个数。
分析:直接思路:通过判断运算符符号,对这两个数进行运算。代码如下所示:
static class Calculator {
private static final String SYMBOL_ADD = "+";
private static final String SYMBOL_SUB = "-";
public int calc(int a, int b, final String symbol) {
int result = 0;
if (SYMBOL_ADD.equals(symbol)) {
result = a + b;
} else if (SYMBOL_ADD.equals(symbol)) {
result = a - b;
}
return result;
}
}
但是这样写的话,如果我们现在要扩展乘法*
或除法/
运算,那么就要在calc方法内增加对应的if...else
判断,代码臃肿并且扩展性太低。
而如果采用策略模式,将各种运算符的计算都归并到对应具体策略,这样,就能简化代码并且带来很好的扩展性,具体代码如下:
class Client {
public static void main(String[] args) {
ICalculator calculator = new Add();
Context context = new Context(calculator);
int result = context.calc(1,2);
System.out.println(result);
}
interface ICalculator {
int calc(int a, int b);
}
static class Add implements ICalculator {
@Override
public int calc(int a, int b) {
return a + b;
}
}
static class Sub implements ICalculator {
@Override
public int calc(int a, int b) {
return a - b;
}
}
static class Multi implements ICalculator {
@Override
public int calc(int a, int b) {
return a * b;
}
}
static class Divide implements ICalculator {
@Override
public int calc(int a, int b) {
return a / b;
}
}
static class Context {
private ICalculator mCalculator;
public Context(ICalculator calculator) {
this.mCalculator = calculator;
}
public int calc(int a, int b) {
return this.mCalculator.calc(a, b);
}
}
}
从上面代码中,我们可以看到,我们完全消除了对运算符号进行判断的哪些if...else
的冗余代码,取而代之的是客户端直接决定使用哪种算法,然后交由上下文获取结果。并且上面代码中我们还扩展了乘法Multi
和除法Divide
运算,所需要做的就只是扩展相应的策略类而已。
原文地址:https://www.cnblogs.com/csh24/p/11813476.html
- Linux | 不懂Linux的码神,不是真正的菜鸟
- 初体验Spring Boot 2支持的HikariCP连接池
- 快来了解JDK10中引入的全新JIT编译器:Graal
- 基于Ryu打造自定义控制器
- Junit 5新特性全集
- 深入了解浏览器的重绘与重排
- 自己动手写区块链(Java版)
- 自己动手写区块链-发起一笔交易(Java版)
- 详解JavaScript跨域问题
- OpenStack Magnum及Liberty新功能简介
- JDK10要来了:下一代 Java 有哪些新特性?
- 是时候忘掉finalize方法了
- 学会一个JVM插件:使用HSDIS反汇编JIT生成的代码
- ONOS 实战分享(一):项目建立、调试到热部署
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何在树莓派4B上设置EMQX开机自启动
- 如何使用 Ktor 快速开发 Web 项目
- 神经网络架构搜索——二值可微分搜索(BATS)
- UEFI 原理与编程 1 - UEFI开发环境EDK2搭建
- 【Unity】瞎做个宝石迷阵吧!(1)——构建场景
- VUE组件传值案例讲解
- 【JAVA】来写个JAVA的HelloWorld吧!
- 如何发布自己的项目到Maven中央仓库?
- 《闲扯Redis八》Redis字典的哈希表执行Rehash过程分析
- 为什么说在Android中请求权限从来都不是一件简单的事情?
- 小知识:如何赋予用户查看所有存储过程和触发器的权限
- ZCU106使用VCU TRD的MIPI的例子
- 一款功能简约到可怜的SQL 客户端
- Kotlin---data class
- sqlmap的使用方法