佛山外贸网站建设精英,山东省建设局注册中心网站,深圳网络推广系统,黄页88网站信息怎么删除文章目录 1 策略模式#xff08;Strategy Pattern#xff09;★1.1 介绍1.2 概述1.3 策略模式的结构1.4 策略模式的优缺点1.5 策略模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析#xff08;Comparator#xff09; #x1f64a… 文章目录 1 策略模式Strategy Pattern★1.1 介绍1.2 概述1.3 策略模式的结构1.4 策略模式的优缺点1.5 策略模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析Comparator 前言本文章为瑞_系列专栏之《23种设计模式》的策略模式篇。本文中的部分图和概念等资料来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及UML图的基本知识和设计模式的6大法则等知识建议阅读 《瑞_23种设计模式_概述》 本系列 - 设计模式 - 链接《瑞_23种设计模式_概述》 ⬇️本系列 - 创建型模式 - 链接 单例模式《瑞_23种设计模式_单例模式》 工厂模式《瑞_23种设计模式_工厂模式》 原型模式《瑞_23种设计模式_原型模式》 抽象工厂模式《瑞_23种设计模式_抽象工厂模式》 建造者模式《瑞_23种设计模式_建造者模式》 ⬇️本系列 - 结构型模式 - 链接 代理模式《瑞_23种设计模式_代理模式》 适配器模式《瑞_23种设计模式_适配器模式》 装饰者模式《瑞_23种设计模式_装饰者模式》 桥接模式《瑞_23种设计模式_桥接模式》 外观模式《瑞_23种设计模式_外观模式》 组合模式《瑞_23种设计模式_组合模式》 享元模式《瑞_23种设计模式_享元模式》 ⬇️本系列 - 行为型模式 - 链接 模板方法模式《瑞_23种设计模式_模板方法模式》 策略模式《瑞_23种设计模式_策略模式》 命令模式《瑞_23种设计模式_命令模式》 职责链模式《后续更新》 状态模式《后续更新》 观察者模式《后续更新》 中介者模式《后续更新》 迭代器模式《后续更新》 访问者模式《后续更新》 备忘录模式《后续更新》 解释器模式《后续更新》 1 策略模式Strategy Pattern★ 瑞工厂模式结合策略模式可以替换 if-else 语句。策略模式主要目的是避免使用多重条件语句并将算法的实现从使用算法的客户端代码中分离出来。 在策略模式Strategy Pattern中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 瑞行为型模式用于描述程序在运行时复杂的流程控制即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务它涉及算法与对象间职责的分配。 瑞行为型模式分为类行为模式和对象行为模式前者采用继承机制来在类间分派行为后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低满足“合成复用原则”所以对象行为模式比类行为模式具有更大的灵活性。 策略模式属于对象行为模式 在策略模式定义了一系列算法或策略并将每个算法封装在独立的类中使得它们可以互相替换。通过使用策略模式可以在运行时根据需要选择不同的算法而不需要修改客户端代码。 在策略模式中我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。 策略模式通过将算法与使用算法的代码解耦提供了一种动态选择不同算法的方法。客户端代码不需要知道具体的算法细节而是通过调用环境类来使用所选择的策略。
1.1 介绍 意图定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。 主要解决在有多种算法相似的情况下使用 if…else 所带来的复杂和难以维护。 何时使用一个系统有许多许多类而区分它们的只是他们直接的行为。 如何解决将这些算法封装成一个一个的类任意地替换。 关键代码实现同一个接口。 应用实例 1️⃣ 诸葛亮的锦囊妙计每一个锦囊就是一个策略。 2️⃣ 旅行的出游方式选择骑自行车、坐汽车每一种旅行方式都是一个策略。 3️⃣ JAVA AWT 中的 LayoutManager。 优点 1️⃣ 算法可以自由切换。 2️⃣ 避免使用多重条件判断。 3️⃣ 扩展性良好。 缺点 1️⃣ 策略类会增多。 2️⃣ 所有策略类都需要对外暴露。 使用场景 1️⃣ 如果在一个系统里面有许多类它们之间的区别仅在于它们的行为那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2️⃣ 一个系统需要动态地在几种算法中选择一种。 3️⃣ 如果一个对象有很多的行为如果不用恰当的模式这些行为就只好使用多重的条件选择语句来实现。 注意事项如果一个系统的策略多于四个就需要考虑使用混合模式解决策略类膨胀的问题。
1.2 概述 定义该模式定义了一系列算法并将每个算法封装起来使它们可以相互替换且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式它通过对算法进行封装把使用算法的责任和算法的实现分割开来并委派给不同的对象对这些算法进行管理。 策略模式是一种灵活且强大的设计模式它适用于需要在不同算法之间进行选择的情况同时保持代码的可维护性和扩展性。比如我们去旅游选择出行模式有很多种可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。作为一个程序猿开发需要选择一款开发工具当然可以进行代码开发的工具有很多可以选择Idea进行开发也可以使用eclipse进行开发也可以使用其他的一些开发工具。
1.3 策略模式的结构
策略模式的主要角色如下 1️⃣ 抽象策略Strategy类这是一个抽象角色通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。 2️⃣ 具体策略Concrete Strategy类实现了抽象策略定义的接口提供具体的算法实现或行为。 3️⃣ 环境Context类持有一个策略类的引用最终给客户端调用。
1.4 策略模式的优缺点
优点 策略类之间可以自由切换 由于策略类都实现同一个接口所以使它们之间可以自由切换。 易于扩展 增加一个新的策略只需要添加一个具体的策略类即可基本不需要改变原有的代码符合“开闭原则“ 避免使用多重条件选择语句if else充分体现面向对象设计思想。
缺点
客户端必须知道所有的策略类并自行决定使用哪一个策略类。策略模式将造成产生很多策略类可以通过使用享元模式在一定程度上减少对象的数量。
1.5 策略模式的使用场景
一个系统需要动态地在几种算法中选择一种时可将每个算法封装到策略类中。一个类定义了多种行为并且这些行为在这个类的操作中以多个条件语句的形式出现可将每个条件分支移入它们各自的策略类中以代替这些条件语句。系统中各算法彼此完全独立且要求对客户隐藏具体算法的实现细节时。系统要求使用算法的客户不应该知道其操作的数据时可使用策略模式来隐藏与算法相关的数据结构。多个类只区别在表现行为不同可以使用策略模式在运行时动态选择具体要执行的行为。
2 案例一 【案例】促销活动 2.1 需求 一家百货公司在定年度的促销活动。针对不同的节日春节、中秋节、圣诞节推出不同的促销活动由促销员将促销活动展示给客户。类图如下 2.2 代码实现 定义百货公司所有促销活动的共同接口
抽象策略类接口 /*** 抽象策略类** author LiaoYuXing-Ray**/
public interface Strategy {void show();
} 定义具体策略角色Concrete Strategy每个节日具体的促销活动
为春节准备的促销活动A类 /*** 为春节准备的促销活动A* 具体策略类封装算法** author LiaoYuXing-Ray**/
public class StrategyA implements Strategy {public void show() {System.out.println(春节买一送一);}
}为中秋准备的促销活动B类 /*** 为中秋准备的促销活动B* 具体策略类封装算法** author LiaoYuXing-Ray**/
public class StrategyB implements Strategy {public void show() {System.out.println(中秋满200元减50元);}
}
为圣诞准备的促销活动C类 /*** 为圣诞准备的促销活动C* 具体策略类封装算法** author LiaoYuXing-Ray**/
public class StrategyC implements Strategy {public void show() {System.out.println(圣诞满1000元加一元换购任意200元以下商品);}
} 定义环境角色Context用于连接上下文即把促销活动推销给客户这里可以理解为销售员
促销员环境角色类 /*** 促销员(环境类)** author LiaoYuXing-Ray**/
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 salesManShow() {strategy.show();}
}
测试类 /*** 测试类** author LiaoYuXing-Ray**/
public class Client {public static void main(String[] args) {// 春节来了使用春节促销活动SalesMan salesMan new SalesMan(new StrategyA());// 展示促销活动salesMan.salesManShow();System.out.println();// 中秋节到了使用中秋节的促销活动salesMan.setStrategy(new StrategyB());// 展示促销活动salesMan.salesManShow();System.out.println();// 圣诞节到了使用圣诞节的促销活动salesMan.setStrategy(new StrategyC());// 展示促销活动salesMan.salesManShow();}
} 代码运行结果如下 春节买一送一中秋满200元减50元圣诞满1000元加一元换购任意200元以下商品3 案例二 本案例为菜鸟教程中的案例 3.1 需求 我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。 StrategyPatternDemo我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。 3.2 代码实现
步骤 1 创建一个接口。
Strategy.java public interface Strategy {public int doOperation(int num1, int num2);
}步骤 2 创建实现接口的实体类。
OperationAdd.java public class OperationAdd implements Strategy{Overridepublic int doOperation(int num1, int num2) {return num1 num2;}
}OperationSubtract.java public class OperationSubtract implements Strategy{Overridepublic int doOperation(int num1, int num2) {return num1 - num2;}
}OperationMultiply.java public class OperationMultiply implements Strategy{Overridepublic int doOperation(int num1, int num2) {return num1 * num2;}
}步骤 3 创建 Context 类。
Context.java public class Context {private Strategy strategy;public Context(Strategy strategy){this.strategy strategy;}public int executeStrategy(int num1, int num2){return strategy.doOperation(num1, num2);}
}步骤 4 使用 Context 来查看当它改变策略 Strategy 时的行为变化。
StrategyPatternDemo.java public class StrategyPatternDemo {public static void main(String[] args) {Context context new Context(new OperationAdd()); System.out.println(10 5 context.executeStrategy(10, 5));context new Context(new OperationSubtract()); System.out.println(10 - 5 context.executeStrategy(10, 5));context new Context(new OperationMultiply()); System.out.println(10 * 5 context.executeStrategy(10, 5));}
}步骤 5 执行程序输出结果 10 5 1510 - 5 510 * 5 504 JDK源码解析Comparator Comparator中的策略模式。在Arrays类中有一个sort() 方法如下
public class Arrays{public static T void sort(T[] a, Comparator? super T c) {if (c null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);}}
}Arrays就是一个环境角色类这个sort方法可以传一个新策略让Arrays根据这个策略来进行排序。就比如下面的测试类。
public class demo {public static void main(String[] args) {Integer[] data {12, 2, 3, 2, 4, 5, 1};// 实现降序排序Arrays.sort(data, new ComparatorInteger() {public int compare(Integer o1, Integer o2) {return o2 - o1;}});System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1]}
}这里我们在调用 Arrays 的 sort 方法时第二个参数传递的是 Comparator 接口的子实现类对象。所以 Comparator 充当的是抽象策略角色而具体的子实现类充当的是具体策略角色。环境角色类Arrays应该持有抽象策略的引用来调用。那么Arrays 类的 sort 方法到底有没有使用 Comparator 子实现类中的 compare() 方法吗让我们继续查看TimSort类的 sort() 方法代码如下
class TimSortT {static T void sort(T[] a, int lo, int hi, Comparator? super T c,T[] work, int workBase, int workLen) {assert c ! null a ! null lo 0 lo hi hi a.length;int nRemaining hi - lo;if (nRemaining 2)return; // Arrays of size 0 and 1 are always sorted// If array is small, do a mini-TimSort with no mergesif (nRemaining MIN_MERGE) {int initRunLen countRunAndMakeAscending(a, lo, hi, c);binarySort(a, lo, hi, lo initRunLen, c);return;}...} private static T int countRunAndMakeAscending(T[] a, int lo, int hi,Comparator? super T c) {assert lo hi;int runHi lo 1;if (runHi hi)return 1;// Find end of run, and reverse range if descendingif (c.compare(a[runHi], a[lo]) 0) { // Descendingwhile (runHi hi c.compare(a[runHi], a[runHi - 1]) 0)runHi;reverseRange(a, lo, runHi);} else { // Ascendingwhile (runHi hi c.compare(a[runHi], a[runHi - 1]) 0)runHi;}return runHi - lo;}
}上面的代码中最终会跑到 countRunAndMakeAscending() 这个方法中。我们可以看见只用了 compare 方法所以在调用 Arrays.sort 方法只传具体 compare 重写方法的类对象就行这也是 Comparator 接口中必须要子类实现的一个方法。 本文是博主的粗浅理解可能存在一些错误或不完善之处如有遗漏或错误欢迎各位补充谢谢 如果觉得这篇文章对您有所帮助的话请动动小手点波关注你的点赞收藏⭐️转发评论都是对博主最好的支持~