目录
一、行为型模式
1.1、策略模式
1.1.1、概论
策略模式设计的每一个算法都封装了起来,使他们可以相互替换,通过一个对象委派不同的算法给相应的客户进行使用.
例如一家百货公司,规定在逢年过节的时候进行促销活动. 针对不同的节日(春节、中秋节、端午节)推出不同的促销活动,然后由 促销员 将促销活动展示给客户.
策略模式主要角色如下:
- 抽象策略类:由一个接口或者抽象类来实现,给出了所有 具体策略类 所需的接口.
- 提交策略类:实现了抽下你个策略定义的接口,提供具体的算法实现.
- 环境类:持有一个策略类引用,最终给客户端调用.
1.1.2、案例实现
针对以上案例进行实现.
/**
* 抽象策略: 促销活动接口
*/
public interface Strategy {
void show();
}
/**
* 具体策略类: 春节活动类
*/
public class StrategyA implements Strategy {
@Override
public void show() {
System.out.println("春节到了,全场买一送一!");
}
}
/**
* 具体策略类: 中秋节活动类
*/
public class StrategyB implements Strategy {
@Override
public void show() {
System.out.println("中秋节到了,全场满 50 送月饼!");
}
}
/**
* 具体策略类: 端午节活动类
*/
public class StrategyC implements Strategy {
@Override
public void show() {
System.out.println("端午节到了,全场满 80 送粽子!");
}
}
/**
* 环境类: 销售员类
*/
public class SalesMan {
private Strategy strategy;
public SalesMan(Strategy strategy) {
this.strategy = strategy;
}
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void showAction() {
strategy.show();
}
}
public class Client {
public static void main(String[] args) {
//1.春节
SalesMan man = new SalesMan(new StrategyA());
man.showAction();
System.out.println("======================");
//2.中秋节
man.setStrategy(new StrategyB());
man.showAction();
System.out.println("======================");
//3.端午节
man.setStrategy(new StrategyC());
man.showAction();
System.out.println("======================");
}
}
执行结果如下:
1.1.3、案例实现(项目实战)
在博客系统中,发布文章常常有很多种不同的状态,比如普通发布、私密发布、定时发布...... 如果单纯使用 when 语句的话,会导致业务代码耦合度高. 因此这里非常适合使用策略模式,选择指定的策略来进行文章的发布.
data class Article (
val title: String,
val content: String,
)
//定义发布策略接口
interface ArticlePubStrategy {
fun publish(article: Article)
}
//普通发布-策略实现
class NormalPubStrategy: ArticlePubStrategy {
override fun publish(article: Article) {
//实现普通发布逻辑
println("normal article save to db! title: ${article.title}")
}
}
//私密发布-策略实现
class PrivatePubStrategy: ArticlePubStrategy {
override fun publish(article: Article) {
//实现私密发布逻辑
println("private article save to db! title: ${article.title}")
}
}
//定时发布-策略实现
class TimedPubStrategy: ArticlePubStrategy {
override fun publish(article: Article) {
//实现定时发布逻辑
println("time article save to db! title: ${article.title}")
}
}
//环境类: 策略上下文,用来选择策略
class ArticlePubContext(
var articlePubStrategy: ArticlePubStrategy
) {
fun publish(article: Article) {
articlePubStrategy.publish(article)
}
}
fun main() {
val pubContext = ArticlePubContext(NormalPubStrategy())
val article = Article(
title = "Spring | Home",
content = "Level up your Java™ code. With Spring Boot in your app.",
)
//正常发布
pubContext.publish(article)
println("=========================================")
//私密发布
pubContext.articlePubStrategy = PrivatePubStrategy()
pubContext.publish(article)
println("=========================================")
//定时发布
pubContext.articlePubStrategy = TimedPubStrategy()
pubContext.publish(article)
}
运行效果如下:
1.1.4、优缺点
优点:
- 策略类之间可以自由切换:由于策略类都实现同一个接口,所以使得他们之间可以根据不同的需求场景任意切换.
- 易扩展,符合开闭原则:增加一个新的的策略只需要添加一个具体的策略类即可,不需要修改原有代码.
- 避免使用多重条件选择语句(if else),充分体现面向对象设计思想.
缺点:
客户端必须知道所有的策略类,并自行决定使用哪个策略类.
策略模式将造成产生多个策略类(一个策略产生一个类).
1.1.5、使用场景
- 一个系统需要动态的在几种算法中选择一种时,可以将每个算法封装到策略类中.
- 一个类定义了多个行为,并且这些行为在这个类中以多个条件语句(if else)出现,就可以将每个分支移入他们各自的策略类中以替代这些条件语句.
- 每个策略算法彼此独立,要对客户隐藏具体算法实现细节.