0

0

Java中策略模式和模板方法模式的介绍(附代码)

不言

不言

发布时间:2019-02-19 15:56:37

|

2791人浏览过

|

来源于博客园

转载

本篇文章给大家带来的内容是关于Java中策略模式和模板方法模式的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

策略模式

简介

策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。其主要目的是通过定义相似的算法,替换if else 语句写法,并且可以随时相互替换。

策略模式主要由这三个角色组成,环境角色(Context)、抽象策略角色(Strategy)和具体策略角色(ConcreteStrategy)。

  • 环境角色(Context):持有一个策略类的引用,提供给客户端使用。

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

  • 具体策略角色(ConcreteStrategy):包装了相关的算法或行为。

    立即学习Java免费学习笔记(深入)”;

示例图如下:
在这里插入图片描述

这里为了方便理解,我们就拿刚学习Java的时候使用计算方法来说吧。
在使用计算器进行计算的时候,会经常用到加减乘除方法。如果我们想得到两个数字相加的和,我们需要用到“+”符号,得到相减的差,需要用到“-”符号等等。虽然我们可以通过字符串比较使用if/else写成通用方法,但是计算的符号每次增加,我们就不得不加在原先的方法中进行增加相应的代码,如果后续计算方法增加、修改或删除,那么会使后续的维护变得困难。
但是在这些方法中,我们发现其基本方法是固定的,这时我们就可以通过策略模式来进行开发,可以有效避免通过if/else来进行判断,即使后续增加其他的计算规则也可灵活进行调整。

首先定义一个抽象策略角色,并拥有一个计算的方法。

interface CalculateStrategy {
   int doOperation(int num1, int num2);
}

然后再定义加减乘除这些具体策略角色并实现方法。

那么代码如下:

class OperationAdd implements CalculateStrategy {
   @Override   public int doOperation(int num1, int num2) {
          return num1 + num2;
   }
}
class OperationSub implements CalculateStrategy {
   @Override   public int doOperation(int num1, int num2) {
          return num1 - num2;
   }
}
class OperationMul implements CalculateStrategy {
   @Override   public int doOperation(int num1, int num2) {
          return num1 * num2;
   }
}
class Operationp implements CalculateStrategy {
   @Override   public int doOperation(int num1, int num2) {
          return num1 / num2;
   }
}

最后在定义一个环境角色,提供一个计算的接口供客户端使用。
代码如下:

class  CalculatorContext {
    private CalculateStrategy strategy;
    public CalculatorContext(CalculateStrategy strategy) {
            this.strategy = strategy;
    }    
    public int executeStrategy(int num1, int num2) {
            return strategy.doOperation(num1, num2);
    }
}

编写好之后,那么我们来进行测试。
测试代码如下:

    public static void main(String[] args) {
          int a=4,b=2;
          CalculatorContext context = new CalculatorContext(new OperationAdd());    
          System.out.println("a + b = "+context.executeStrategy(a, b));
     
          CalculatorContext context2 = new CalculatorContext(new OperationSub());      
          System.out.println("a - b = "+context2.executeStrategy(a, b));
     
          CalculatorContext context3 = new CalculatorContext(new OperationMul());    
          System.out.println("a * b = "+context3.executeStrategy(a, b));
    
          CalculatorContext context4 = new CalculatorContext(new Operationp());    
          System.out.println("a / b = "+context4.executeStrategy(a, b));
}

输出结果:

a + b = 6
a - b = 2
a * b = 8
a / b = 2

策略模式优点:

扩展性好,可以在不修改对象结构的情况下,为新的算法进行添加新的类进行实现;
灵活性好,可以对算法进行自由切换;

策略模式缺点:

使用策略类变多,会增加系统的复杂度。;
客户端必须知道所有的策略类才能进行调用;

使用场景:

如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为;
一个系统需要动态地在几种算法中选择一种;
如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现;

模板模式

简介

模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 这种类型的设计模式属于行为型模式。定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

PaperFake
PaperFake

AI写论文

下载

模板模式,其主要的的思想就是做一个模板,提供给客户端进行调用。除去生活中我们经常用到的简历模板、合同模板等等,Java中也有很经典的模板使用,那就是Servlet,HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体则由子类提供。

模板模式主要由抽象模板(Abstract Template)角色和具体模板(Concrete Template)角色组成。

  • 抽象模板(Abstract Template): 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤;定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

  • 具体模板(Concrete Template): 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤;每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

示例图如下:
https://www.dofactory.com/images/diagrams/net/template.gif

这里为了方便理解,我们依旧使用一个简单的示例来加以说明。
我们以前在玩魂斗罗、双截龙、热血物语、忍者神龟等等游戏的时候,都需要在小霸王游戏机上插卡,然后启动游戏才能玩,其中魂斗罗这种游戏,启动游戏之后就可以直接玩了,但是忍者神龟这种游戏则在启动游戏之后,需要选择其中一个角色才能开始玩。那么我们可以根据这个场景写出一个通用的模板,主要包含启动游戏,玩游戏,结束游戏这几个必须实现的方法,选择人物这个方法改成可选。

那么这个抽象类的代码如下:

abstract class  Game{    
    //启动游戏    
    protected abstract void  runGame();    
    //选择人物    
    protected  void choosePerson() {};    
    //开始玩游戏    
    protected abstract void startPlayGame();    
    //结束游戏    
    protected abstract void endPlayGame();    
    //模板方法    
    public final void play() {
        runGame();
        choosePerson();
        startPlayGame();
        endPlayGame();
    }
    
}

定义好该抽象类之后,我们再来定义具体模板实现类。这里定义两个游戏类,一个是魂斗罗,一个忍者神龟。

那么代码如下:

class ContraGame extends Game{   @Override   protected void runGame() {
       System.out.println("启动魂斗罗II...");
   }   
@Override   protected void startPlayGame() {
          System.out.println("1P正在使用S弹打aircraft...");
   }   
@Override   protected void endPlayGame() {
          System.out.println("1P被流弹打死了,游戏结束!");
   }
}
class TMNTGame extends Game{
   @Override   protected void runGame() { 
         System.out.println("启动忍者神龟III...");
   }   
   @Override   protected void choosePerson() {       System.out.println("1P选择了Raph !");
   }   
   @Override   protected void startPlayGame() {
          System.out.println("Raph正在使用绝技 “火箭头槌” ");
   }   
   @Override   protected void endPlayGame() {
          System.out.println("Raph 掉进井盖里死了,游戏结束了! ");
   }
}

最后再来进行测试,测试代码如下:

public static void main(String[] args) {
       Game game = new ContraGame();
       game.play();
       System.out.println();
       game = new TMNTGame();
       game.play();

}

输出结果:

启动魂斗罗II...1P正在使用S弹打aircraft...1P被流弹打死了,游戏结束!

启动忍者神龟III...1P选择了Raph !
Raph正在使用绝技 “火箭头槌” 
Raph 掉进井盖里死了,游戏结束了!

模板模式优点:

扩展性好,对不变的代码进行封装,对可变的进行扩展;
可维护性好,因为将公共代码进行了提取,使用的时候直接调用即可;

模板模式缺点:

因为每一个不同的实现都需要一个子类来实现,导致类的个数增加,会使系统变得复杂;

使用场景:

有多个子类共有逻辑相同的方法;
重要的、复杂的方法,可以考虑作为模板方法。

注意事项:

为防止恶意操作,一般模板方法都加上 final 关键词!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
servlet生命周期
servlet生命周期

Servlet生命周期是指Servlet从创建到销毁的整个过程。本专题为大家提供servlet生命周期的各类文章,大家可以免费体验。

393

2023.08.08

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

761

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1568

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

651

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1228

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

1204

2024.04.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.3万人学习

Java 教程
Java 教程

共578课时 | 81.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号