模式包含以下主要角色:
抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。
抽象类:
- //抽象类:定义模板方法和基本方法
- public abstract class AbstractClass {
-
- //模板方法
- public final void cookProcess() {
- pourOil();
- heatOil();
- pourVegetable();
- pourSauce();
- fry();
- }
-
- //具体方法
- //第二步:倒油是一样的,所以直接实现
- public void pourOil() {
- System.out.println("倒油");
- }
-
- //第二步:热油是一样的,所以直接实现
- public void heatOil() {
- System.out.println("热油");
- }
-
- //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
- public abstract void pourVegetable();
-
- //第四步:倒调味料是不一样
- public abstract void pourSauce();
-
- //第五步:翻炒是一样的,所以直接实现
- public void fry(){
- System.out.println("炒啊炒啊炒到熟啊");
- }
- }
具体子类:
- //炒包菜类
- public class ConcreteClass_BaoCai extends AbstractClass {
-
- public void pourVegetable() {
- System.out.println("下锅的蔬菜是包菜");
- }
-
- public void pourSauce() {
- System.out.println("下锅的酱料是辣椒");
- }
- }
-
-
- //炒菜心类
- public class ConcreteClass_CaiXin extends AbstractClass {
-
- public void pourVegetable() {
- System.out.println("下锅的蔬菜是菜心");
- }
-
- public void pourSauce() {
- System.out.println("下锅的酱料是蒜蓉");
- }
- }
测试类:
- //测试类
- public class Client {
- public static void main(String[] args) {
- //炒包菜
- //创建对象
- ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
- //调用炒菜的功能
- baoCai.cookProcess();
- }
- }
算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
策略模式的主要角色如下:
抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
环境(Context)类:持有一个策略类的引用,最终给客户端调用。
抽象策略类:
- //抽象策略类
- public interface Strategy {
- void show();
- }
具体策略类:
- //具体策略类,封装算法
- public class StrategyA implements Strategy {
- public void show() {
- System.out.println("买一送一");
- }
- }
-
- //具体策略类,封装算法
- public class StrategyB implements Strategy {
- public void show() {
- System.out.println("满200元减50元");
- }
- }
-
- //具体策略类,封装算法
- public class StrategyC implements Strategy {
- public void show() {
- System.out.println("满1000元加一元换购任意200元以下商品");
- }
- }
环境类:
- //促销员:环境类,最终给客户端调用。
- 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();
- }
- }
测试类:
- //测试类
- 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();
- }
- }
1,优点:
策略类之间可以自由切换
由于策略类都实现同一个接口,所以使它们之间可以自由切换。
易于扩展
增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“
避免使用多重条件选择语句(if else),充分体现面向对象设计思想。
2,缺点:
客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。
一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
public class demo {
public static void main(String[] args) {Integer[] data = {12, 2, 3, 2, 4, 5, 1};
// 实现降序排序
Arrays.sort(data, new Comparator() {
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});//匿名内部类,Comparator子实现类
System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1]
}
}
在调用Arrays的sort方法时,第二个参数传递的是Comparator接口的子实现类对象。所以Comparator充当的是抽象策略角色,而具体的子实现类充当的是具体策略角色。环境角色类(Arrays)应该持有抽象策略的引用来调用。Arrays类的sort方法使用的是Comparator子实现类中的Compare() 方法