策略模式(政策模式):定义、场景、UML类图全解析
定义:

策略模式也被称作政策模式。它把定义好的算法家族分别进行封装。这样能使它们之间可以相互替换。通过这种方式,即便算法发生变化,也不会对使用算法的用户产生影响。它属于行为型设计模式。
策略模式运用了面向对象的继承和多态机制,这样就能让同一行为在不同的场景中拥有不同的实现。
场景:
针对同一类型问题,有多种处理方式,每一种都能独立解决问题
需要自由切换算法的场景
需要屏蔽算法规则的场景
UML类图:
右上图可以看出,策略模式主要包含3个角色
上下文环境用于操作策略,它屏蔽了高层模块(客户端)对策略和算法的直接访问,并且能够封装可能存在的变化。
抽象策略角色(IStrategy):规定策略或者算法行为
具体策略角色指的是具体的策略或者算法的实现。
策略模式的上下文角色,它的职责在于隔离客户端与策略类之间的耦合。这样一来,客户端能够完全与上下文进行沟通,而无需去关心具体的策略。
通用写法:
public class Client{
此函数用于程序的入口点,程序从这里开始执行。
//选择一个具体策略
创建了一个名为 iStrategy 的对象,它的类型是 IStrategy,并且将其初始化为一个 ConcreteStrategyA 的实例。
//创建一个上下文环境
创建一个名为 Context 的对象,该对象的构造函数接收一个名为 iStrategy 的参数,即 Context context = new Context(iStrategy)。
context.algorthnm();
}
}
//抽象策略类IStrategy
interface IStrategy{
void algorthnm();
}
//上下文环境
public class Context{
private IStrategy iStrategy;
公共的 Context(IStrategy iStrategy)。
this 的 iStrategy 被赋值为 iStrategy 。
}
public void algorthnm(){
this 调用了 iStrategy 的 algorthnm 方法。
}
}
//具体的策略类ConcreteStrategyA
公共类 ConcreteStrategyA 实现了 IStrategy 接口。
public void algorthnm(){
//具体的策略
}
}
//具体的策略类ConcreteStrategyB
公共类 ConcreteStrategyB 实现了 IStrategy 接口。
public void algorthnm(){
//具体的策略
}
}
举例:
刘备要前往江东娶老婆啦。在出发之前,诸葛亮给了赵云(伴郎)三个锦囊妙计,告知他按照天机依次拆开便可解决棘手问题。嘿,还真别说,这些锦囊妙计真的解决了大问题呢。最终的结果是周瑜赔了夫人又折兵呀。那我们先来看看这个场景究竟是什么样子的。
首先明确这个场景所包含的要素:存在三个妙计,还有一个锦囊,以及一个名为赵云的人。这些妙计是由小亮同志提供的,并且被放置在锦囊中,通常人们将其称为锦囊妙计。赵云是负责执行任务的人,他从锦囊中取出妙计并加以执行,最终取得了胜利。那么,用 JAVA 程序该如何表现这一过程呢?我们先来看看类图。
三个妙计是同一类型的东东,那咱就写个接口:
package com.design.strategy;
/**
首先确定一个策略接口,这个接口是诸葛亮老人家给予赵云的三个锦囊妙计的接口。
*
*/
public interface IStrategy {
//每个锦囊妙计都是一个可执行的算法
public void operate();
}
然后再写三个实现类,有三个妙计嘛:
package com.design.strategy;
/**
* 找乔国老帮忙,使孙权不能杀刘备
*/
公共类 BackDoor 实现了 IStrategy 接口。
public void operate() {
找乔国老去帮忙,让他去促使吴国太给孙权施加压力。
}
}
package com.design.strategy;
/**
* 求吴国太开个绿灯
*/
一个名为 GivenGreenLight 的类实现了 IStrategy 接口。
public void operate() {
请求吴国太打开一个绿灯,让其放行。
}
}
package com.design.strategy;
/**
* 孙夫人断后,挡住追兵
*/
公共类 BlockEnemy 实现了 IStrategy 接口。
public void operate() {
孙夫人进行断后行动,将追兵给挡住了。
}
}
大家看看,现在有了三个妙计,可是需要一个地方来放置这些妙计,也就是放锦囊。
package com.design.strategy;
/**
* 计谋有了,那还要有锦囊
*/
public class Context {
//构造函数,你要使用那个妙计
private IStrategy straegy;
公共的上下文(IStrategy 策略)。
this.straegy = strategy;
}
//使用计谋了,看我出招了
public void operate(){
this.straegy.operate();
}
}
然后赵云怀揣着三个锦囊,雄赳赳地拉着刘老爷子去入赘。刘老爷子已步入老年行列,还想着娶纯情少女,眼神色迷迷的。嗨,别说,小亮的三个妙计确实不错,瞧瞧:
package com.design.strategy;
public class ZhaoYun {
/**
* 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计
*/
公共静态 void 主函数(字符串数组 args){
Context context;
//刚刚到吴国的时候拆第一个
System.out.println("刚刚到达吴国的时候,要拆第一个。");
使用新的上下文对象并传入一个后门对象,从而获取到妙计。
context.operate(); //拆开执行
输出多个换行符,即输出了 9 个换行符。
//刘备乐不思蜀了,拆第二个了
System.out.println("-----------刘备开始乐不思蜀了,开始拆第二个了-------------");
创建了一个新的 Context,这个 Context 关联了一个新的 GivenGreenLight。
执行了第二个锦囊。
System.out.println("\n\n\n\n\n\n\n\n");
//孙权的小兵追了,咋办?拆第三个
System.out.println("孙权的小兵追来了,该怎么办呢?拆解第三个。")
-------------");
创建了一个新的 Context 对象,该对象的构造函数传入了一个新的 BlockEnemy 对象。
context.operate(); //孙夫人退兵
System.out.println("\n\n\n\n\n\n\n\n");
}
}
这三招搞得周郎“陪了夫人又折兵”。这体现了策略模式,其高内聚低耦合的特点得以展现。同时还有扩展性,即遵循 OCP 原则,策略类能够继续增加,只需修改 Context.java 即可,此处不再赘述,自行领会。
策略模式优缺点: 优点:
策略模式符合开闭原则
不要使用像 if.....else 或者 switch....case 这样的多重条件转移语句。
使用策略模式可以提高算法的保密性和安全性
缺点:
客户端必须要知道所有的策略,并且自行决定使用哪一个策略类
代码中会产生非常多的策略类,增加维护难度