• 设计模式——模板方法模式、策略模式(行为型模式)


    1.模板方法模式

    模式包含以下主要角色:

    • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。

      • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

      • 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:

        • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。

        • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。

        • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

          一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。

    • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。

    抽象类:

    1. //抽象类:定义模板方法和基本方法
    2. public abstract class AbstractClass {
    3. //模板方法
    4. public final void cookProcess() {
    5. pourOil();
    6. heatOil();
    7. pourVegetable();
    8. pourSauce();
    9. fry();
    10. }
    11. //具体方法
    12. //第二步:倒油是一样的,所以直接实现
    13. public void pourOil() {
    14. System.out.println("倒油");
    15. }
    16. //第二步:热油是一样的,所以直接实现
    17. public void heatOil() {
    18. System.out.println("热油");
    19. }
    20. //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
    21. public abstract void pourVegetable();
    22. //第四步:倒调味料是不一样
    23. public abstract void pourSauce();
    24. //第五步:翻炒是一样的,所以直接实现
    25. public void fry(){
    26. System.out.println("炒啊炒啊炒到熟啊");
    27. }
    28. }

    具体子类:

    1. //炒包菜类
    2. public class ConcreteClass_BaoCai extends AbstractClass {
    3. public void pourVegetable() {
    4. System.out.println("下锅的蔬菜是包菜");
    5. }
    6. public void pourSauce() {
    7. System.out.println("下锅的酱料是辣椒");
    8. }
    9. }
    10. //炒菜心类
    11. public class ConcreteClass_CaiXin extends AbstractClass {
    12. public void pourVegetable() {
    13. System.out.println("下锅的蔬菜是菜心");
    14. }
    15. public void pourSauce() {
    16. System.out.println("下锅的酱料是蒜蓉");
    17. }
    18. }

    测试类:

    1. //测试类
    2. public class Client {
    3. public static void main(String[] args) {
    4. //炒包菜
    5. //创建对象
    6. ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
    7. //调用炒菜的功能
    8. baoCai.cookProcess();
    9. }
    10. }

    适用场景

    • 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。

    • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制

    2.策略模式

    策略模式的主要角色如下:

    • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

    • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。

    • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

    抽象策略类:

    1. //抽象策略类
    2. public interface Strategy {
    3. void show();
    4. }

    具体策略类:

    1. //具体策略类,封装算法
    2. public class StrategyA implements Strategy {
    3. public void show() {
    4. System.out.println("买一送一");
    5. }
    6. }
    7. //具体策略类,封装算法
    8. public class StrategyB implements Strategy {
    9. public void show() {
    10. System.out.println("满200元减50元");
    11. }
    12. }
    13. //具体策略类,封装算法
    14. public class StrategyC implements Strategy {
    15. public void show() {
    16. System.out.println("满1000元加一元换购任意200元以下商品");
    17. }
    18. }

    环境类:

    1. //促销员:环境类,最终给客户端调用。
    2. public class SalesMan {
    3. //聚合策略类对象
    4. private Strategy strategy;
    5. public SalesMan(Strategy strategy) {
    6. this.strategy = strategy;
    7. }
    8. public Strategy getStrategy() {
    9. return strategy;
    10. }
    11. public void setStrategy(Strategy strategy) {
    12. this.strategy = strategy;
    13. }
    14. //由促销员展示促销活动给用户
    15. public void salesManShow() {
    16. strategy.show();
    17. }
    18. }

    测试类:

    1. //测试类
    2. public class Client {
    3. public static void main(String[] args) {
    4. //春节来了,使用春节促销活动
    5. SalesMan salesMan = new SalesMan(new StrategyA());
    6. salesMan.salesManShow();
    7. System.out.println("==============");
    8. //中秋节到了,使用中秋节的促销活动
    9. salesMan.setStrategy(new StrategyB());
    10. salesMan.salesManShow();
    11. System.out.println("==============");
    12. //圣诞节到了,使用圣诞节的促销活动
    13. salesMan.setStrategy(new StrategyC());
    14. salesMan.salesManShow();
    15. }
    16. }

    优缺点

    1,优点:

    • 策略类之间可以自由切换

      由于策略类都实现同一个接口,所以使它们之间可以自由切换。

    • 易于扩展

      增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“

    • 避免使用多重条件选择语句(if else),充分体现面向对象设计思想。

    2,缺点:

    • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

    • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

    使用场景

    • 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。

    • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。

    • 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。

    • 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。

    • 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。

    Comparator中的策略模式

    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() 方法

  • 相关阅读:
    Java基础:Stream流和方法引用
    Arduino 基础语法
    爬虫玩得好,牢饭吃到饱?这3条底线千万不能碰!
    【SpringMVC】集成Web、MVC执行流程、数据响应、数据交互
    sudo漏洞
    C Primer Plus(6) 中文版 第2章 C语言概述 2.5 进一步使用C
    [附源码]Python计算机毕业设计Django个性化名片网站
    Hadoop3教程(二十一):MapReduce中的压缩
    服务器三大作用域:Request,ServletContext,Session
    10 个最佳地理空间数据分析 GIS 软件
  • 原文地址:https://blog.csdn.net/m0_63544124/article/details/126027302