利用策略模式消除多个条件语句但是不是面向对象
要解决的问题:
条件分支过多,扩展性差
如何解决:
把分支内容进行封装,放入不同策略
优点:
耦合性降低,可扩展性提高
TLDR;
OOP 设计模式的策略模式有以下几点适用性是我使用策略模式消除多个条件语句的原因
-
许多相关的类仅仅行为不同,“策略”提供了一种用多个(类似的)行为中的一个行为来形成一个类的方法。
-
也就是把每种行为都封装到一个策略类里边
2. 一个类定义了多种行为,并且这些行为在这个类的操作中,以多个条件语句的形式出现。 将相关的条件分支移入它们各自的Strategy(策略)类中以代替这些条件语句。
便于快速理解(但稍显粗糙)理解
策略模式
就是将处理同一个问题的不同的类似方法封装到名字不同(当然),
但是形式上相同的类里边,这些类都叫他们策略类,
由使用者(指客户类)自行决定该使用什么策略 ,而不是程序员手动写成 多个条件分支。
《设计模式》 P.234
![](file://C:\Users\jay\AppData\Roaming\marktext\images\2022-08-03-16-04-45-image.png?msec=1660098424075)
便于快速理解(但稍显粗糙)解答
假设要处理问题A,可以采取A1到An ,n种方法,
然后你发现n种方法极其类似,因为他们都是处理A问题的 方法。
那么默认情况下,妮可能这么处理
if(case==="1"){
// A1方法 的逻辑
}
else if(case==="2"){
// A2方法的逻辑
}
// ... n个 可能的分支
当使用策略模式的时候,我们可以这么重构
// 当 存在 策略类A1,A2...An 分别封装了A1和A2方法的具体逻辑
// 并且A1,A2...An上一定有一个方法(比如名叫shouldUseThis)
class Consumer{
// 由Consumer 接受A1 ,A2...等等类,放到一个列表/map/数组等数据结构里 List
// 在需要处理问题A的时候,可以循环List ,当Ai.shouldUseThis()=== true.
// 就使用Ai 策略
}
具体示例
条件分支很多...
function isLogin(value: possibility) {
if (value === "login" || value === "登录" || value === "lg") {
return true;
}
}
function isMain(value: possibility) {
if (value === "main" || value === "task") {
return true;
}
}
//...
if (isLogin(input)) {
navigate("/login");
} // @ts-ignore
if (isMain(input)) {
navigate("/main");
} // @ts-ignore
if (isChangeColorMode(input)) {
// 这种我可以弄 ,因为是自定义的函数
ChangeAppColorMode.changeColorMode();
} // @ts-ignore
if (isHome(input)) {
// 这种不太好弄 试一试
navigate("/");
}
//@ts-ignore
if (isChangeColorModePreferOs(input)) {
ChangeAppColorMode.preferOsColorMode();
}
改动后 1. isHome、isLogin这样的函数的具体逻辑被封装到策略中
isHome==>useNavigateHomeCmd
# 这个策略是 isHome 转变后的样子
import { useNavigate } from "react-router-dom";
import funnybarHook from "./funnybarHook";
const useNavigateHomeCmd: funnybarHook = function (inputValue: string) {
// the "outer function" which gonna do real executing some command job should be specified here.
// 声明要使用的"外部函数",这个外部函数 就是要执行某项命令实际要调用的函数
const navigate = useNavigate();
/**
you must( i mean ,using my pattern) use this formation,which constitutes 3 steps
1. write a function, whatever its type ,but i think an arrow fn is enough
2. execute the outer fn inside the arrow fn. remember to couple the actual thing you want to do here,say you wanna
navigate your page to '/home', then fix the execTheCmd's arrow fn stuff 'navigate('/home')'
* 3. give the arrow fn a fixed name , which is execTheCmd.
如何暴露"外部函数"?我的思路是分三个步骤
1. 写一个箭头函数
2. 在箭头函数内部执行外部函数,注意,把具体要做的内容放进来,比如你要去/home,就写 navigate('/home')
3. 给箭头函数一个名字,注意,必须是 execTheCmd
*/
const execTheCmd = () => {
navigate("/");
};
/**
* optional at the time
*
*/
const possibility = ["home", "h"];
/**
*
* this fn must have a name 'judge'
* 和前面的execTheCmd 类似, 这个函数名字 必须是 judge
*/
function judge() {
// inputValue === "home" || inputValue === "h"
if (possibility.includes(inputValue)) {
return true;
} else {
return false;
}
}
return { judge, execTheCmd, possibility };
};
export default useNavigateHomeCmd;
另一个isLogin==>useNavigateLoginCmd
# useNavigateLoginCmd
import { useNavigate } from "react-router-dom";
import funnybarHook from "./funnybarHook";
const useNavigateLoginCmd: funnybarHook = function (inputValue: string) {
const navigate = useNavigate();
const execTheCmd = () => {
navigate("/login");
};
/**
* optional at the time
*
*/
const possibility = ["login", "lg", "登录"];
/**
*
* this fn must have a name 'judge'
* 和前面的execTheCmd 类似, 这个函数名字 必须是 judge
*/
function judge() {
// inputValue === "home" || inputValue === "h"
if (possibility.includes(inputValue)) {
return true;
} else {
return false;
}
}
return { judge, execTheCmd, possibility };
};
export default useNavigateLoginCmd;
怎么使用这些策略?
let strategy1= useNavigateHomeCmd(input);
let strategy2= useNavigateLoginCmd(input);
// if (test?.judge() === true) {
// test.execTheCmd();
// } else {
// // clear this thing
// }
let resultArr = [strategy1, strategy2];
// 浙江是一个循环
for (let i = 0; i < resultArr.length; i++) {
let currentItem = resultArr[i];
if (currentItem.judge() === false) {
continue;
} else {
currentItem.execTheCmd();
break;
}
}