java模板/策略模式打怪兽

news2025/1/21 2:52:52

模板&策略模式
实现姿势
我们会从简单到复杂,讲解代码正确的实现姿势,分别为最 Low 方式、常规方式、模板模式和策略模式。
最 Low 方式
假如现在有 3 个奥特曼,都喜欢 “训练,飞翔,打怪兽”

public class OldTiga {
    public void everyDay() {
        System.out.println("迪迦==>飞翔");
        System.out.println("迪迦==>训练");
        System.out.println("迪迦==>光线打怪兽");
    }
}

public class OldDeNa {
    public void everyDay() {
        System.out.println("戴拿==>训练");
        System.out.println("戴拿==>飞翔");
        System.out.println("戴拿==>体术打怪兽");
    }
}

public class OldMonsters {
    public void everyDay() {
        System.out.println("怪兽==>飞翔");
        System.out.println("怪兽==>训练");
        System.out.println("怪兽==>我**就是怪兽,谁敢打我");
    }

}


public class OldLandLight {
    public static void main(String[] args) {
        OldTiga oldTiga = new OldTiga();
        oldTiga.everyDay();
        OldDeNa oldDeNa = new OldDeNa();
        oldDeNa.everyDay();
        OldMonsters oldMonsters = new OldMonsters();
        oldMonsters.everyDay();
    }
}

测试:

这种方式是大家写代码时,最容易使用的方式,上手简单,也容易理解,目前看项目中陈旧的代码,经常能找到它们的影子,下面我们看怎么一步步将其进行重构。

 

常规方式
“训练,飞翔,打怪兽” 其实都是独立的行为,为了不相互影响,我们可以通过函数简单进行封装:

public class RTiga {
    public void fly(){
        System.out.println("迪迦==>飞翔");
    }

    public void training(){
        System.out.println("迪迦==>训练");
    }
    public void fightMonsters(){
        System.out.println("迪迦==>光线打怪兽");
    }
}

public class RDeNa {
    public void fly(){
        System.out.println("戴拿==>飞翔");
    }

    public void training(){
        System.out.println("戴拿==>训练");
    }
    public void fightMonsters(){
        System.out.println("戴拿==>光线打怪兽");
    }
}


public class RMonsters {
    public void fly(){
        System.out.println("怪兽==>飞翔");
    }

    public void training(){
        System.out.println("怪兽==>训练");
    }
    public void fightMonsters(){
        System.out.println("怪兽==>我**就是怪兽,谁敢打我");
    }
}


public class RLandLight {
    public static void main(String[] args) {
        RTiga rTiga = new RTiga();
        rTiga.fly();
        rTiga.training();
        rTiga.fightMonsters();
        RDeNa rDeNa = new RDeNa();
        rDeNa.fly();
        rDeNa.training();
        rDeNa.fightMonsters();
        RMonsters rMonsters = new RMonsters();
        rMonsters.fly();
        rMonsters.training();
        rMonsters.fightMonsters();
    }
}

测试结果:

 

模板模式
定义:一个抽象类公开定义了执行它的方法的方式/模板,它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行,属于行为型模式。

这 3 个奥特曼,因为 “训练,飞翔” 都一样,所以我们可以直接实现出来,但是他们 “打怪兽” 的方式不同,所以封装成抽象方法,需要每个奥特曼单独去实现 “打怪兽” 的方式。

最后再新增一个方法 everyDo(),固定每天的执行流程:


定义抽象奥特曼类

public abstract class Ultraman {
    public void fly(String name){
        System.out.println(name+"==>飞翔");
    }
    public void training(String name){
        System.out.println(name+"==>训练");
    }
    abstract void fightMonsters(String name);
    public void everyDo(String name){
        this.fly(name);
        this.training(name);
        this.fightMonsters(name);
    }
}


每个不同的奥特曼实现自己的打怪兽方法

@Data
@Accessors(chain = true)
public class Tiga extends Ultraman {
    private String name;
    @Override
    void fightMonsters(String name) {
        System.out.println(name+"==>光线打怪兽");
    }
}

@Data
@Accessors(chain = true)
public class DeNa extends Ultraman {
    private String name;
    @Override
    void fightMonsters(String name) {
        System.out.println(name+"==>体术打怪兽");
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Monsters extends Ultraman {
    private String name;
    @Override
    void fightMonsters(String name) {
        System.out.println(name+"==>我**就是怪兽,谁敢打我");
    }
}


在光之国调用

public class LandLight {
    public static void main(String[] args) {
        Tiga tiga = new Tiga().setName("迪迦");
        tiga.everyDo(tiga.getName());
        DeNa deNa = new DeNa().setName("戴拿");
        deNa.everyDo(deNa.getName());
        Monsters monsters = new Monsters("怪兽");
        monsters.everyDo(monsters.getName());
    }
}


测试结果:

 

策略模式
定义:一个类的行为或其算法可以在运行时更改,即我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象,策略对象改变 context 对象的执行算法,属于行为型模式。还是先定义奥特曼抽象类

public abstract class SUltraman {

    public void fly(String name){
        System.out.println(name+"==>飞翔");
    }
    public void training(String name){
        System.out.println(name+"==>训练");
    }
    abstract void fightMonsters(String name);
}

每个奥特曼实现自己的打怪兽方法

@Data
@Accessors(chain = true)
public class STiga extends SUltraman {
    @Override
    void fightMonsters(String name) {
        System.out.println(name+"==>光线打怪兽");
    }
}


@Data
@Accessors(chain = true)
public class SDeNa extends SUltraman {
    @Override
    void fightMonsters(String name) {
        System.out.println(name+"==>体术打怪兽");
    }
}

@Data
public class SMonsters extends SUltraman {
    @Override
    void fightMonsters(String name) {
        System.out.println(name+"==>我**就是怪兽,谁敢打我");
    }
}

这里就是策略模式的重点,我们再看一下策略模式的定义 “我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象”,这里只需要关注策略的执行行为,而不需要关注是谁来执行的,只重视行为本身,而不去重视执行行为的操作者,那么该 contex 对象如下:

public class BeHaviorContext {
    private SUltraman ultraman;
    private String name;
    public BeHaviorContext(SUltraman newUltraman,String newName){
        name = newName;
        ultraman = newUltraman;
    }
    public void setUltraman(SUltraman newUltraman,String newName){
        name = newName;
        ultraman = newUltraman;
    }
    public void everyDo(){
        ultraman.fly(this.name);
        ultraman.training(this.name);
        ultraman.fightMonsters(this.name);
    }
}

光之国的执行测试:

public class SLandLight {
    public static void main(String[] args) {
       BeHaviorContext beHaviorContext = new BeHaviorContext(new STiga(),"迪迦");
       beHaviorContext.everyDo();

       //重新设置新的策略对象
       beHaviorContext.setUltraman(new SDeNa(),"戴拿");
       beHaviorContext.everyDo();

       beHaviorContext.setUltraman(new SMonsters(),"怪兽");
       beHaviorContext.everyDo();
    }
}


执行结果:

我们可以通过给 behaviorContext 传递不同的策略对象,然后来约定 everyDo() 的调用方式。

 

其实这个示例,有点把策略模式讲复杂了,因为纯粹的策略模式,3 个奥特曼只有 fightMonsteres() 方法不同,所以可以把 fightMonsteres() 理解为不同的算法即可。
之所以引入 everyDo(),是因为实际的项目场景中,会经常这么使用,也就是把这个变化的算法 fightMonsteres(),包装到具体的执行流程里面,所以策略模式就看起来没有那么直观,但是核心思想是一样的。

相似:

策略和模板方法模式都可以用来满足开闭原则,使得软件模块在不改变代码的情况下易于扩展;

两种模式都表示通用 function 与该 function 的详细实现的分离,不过它们所提供的粒度有一些差异。

差异:

策略模式:

它基于接口;

客户和策略之间的耦合更加松散;

定义不能被子类改变的 algorithm 的骨架,只有某些操作可以在子类中重写;

父类完全控制 algorithm ,仅将具体的步骤与具体的类进行区分;

绑定是在编译时完成的。

模板模式:

它基于框架或抽象类,甚至可以有一个具有默认实现的具体类。

模块耦合得更紧密;

它通过修改方法的行为来改变对象的内容;

它用于在 algorithm 族之间切换;

它在运行时通过其他 algorithm 完全 replace 一个algorithm 来改变对象的行为;

绑定在运行时完成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/434538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jsp+java自行车租赁租借和买卖系统

自行车租借和买卖系统 系统包括四个模块。1,系统模块,2,车辆管理模块,3.租借车管理模块,4,买卖车管理模块。 1,系统模块包括: 连接数据库,工作人员登录,退出。 2&#…

《类和对象》(中篇)

本文主要介绍类里面的六大默认成员函数 文章目录 前言类的6个默认成员函数1、构造函数1.1 概念1.2 特性 2、析构函数2.1 概念2.2 特性 3 、拷贝构造函数3.1 概念3.2 特性3.3 使用场景 4、运算符重载4.1 规则4.2 赋值运算符重载 5、const 成员6、取地址与const取地址操作符重载总…

Shiro安全框架简介

一、权限管理 1.1 什么是权限管理 基本上只要涉及到用户参数的系统都要进行权限管理,使用权限管理实现了对用户访问系统的控制,不同的用户访问不同的资源。按照安全规则或者安全策略控制用户访问资源,而且只能访问被授权的资源 权限管理包括认…

学成在线笔记+踩坑(1)——项目思路、架构、父工程和基础工程,Gogs使用

【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线牛客面试题 目录 简历-技术架构 项目预览 后台页面 课程管理 媒资管理页面上传视频 新增课程 课程管理页提交审核 审核员审核后发布课程 前台页面 主页 验证码登录…

uniapp系列-超详细教你在uni-app+vue3里通过web-view组件传递信息打开H5页面写入localstorage并解决兼容性

web-view是什么 web-view 是一个 web 浏览器组件,可以用来承载网页的容器,会自动铺满整个页面(nvue 使用需要手动指定宽高)。点击这里直达官网文档点击这里下载我的代码demo本文最下面还有一些常见或者奇怪问题解决方案哦~ 为什…

GMRES算法及Matlab程序

关于GMRES的总结 一些理论以及代码 首先是我们要解决的问题,也就是最常见的问题,即求解 A x b Axb Axb Galerkin条件 krylov子空间 我们所做的GMRES实际上就是在Galerkin条件的扩张下,n o r m ( r ) normnorm不断减小的一个过程。这也是…

家用洗地机哪种好?性价比高的洗地机推荐

选择清洁家电时,首先需要考虑你需要清洁的区域和清洁的方式。如果你需要清洁的是地面,那么洗地机可能是一个不错的选择。洗地机的优势在于它可以自动清洁地面,并且可以在较短的时间内完成清洁工作。相比于其他的清洁家电,洗地机的…

设计链表(链表篇)

你可以选择使用单链表或者双链表,设计并实现自己的链表。 单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。 如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点…

Linux_红帽8学习笔记分享_5

Linux_红帽8学习笔记分享_5 文章目录 Linux_红帽8学习笔记分享_51. UMASK反掩码1.1如何查看反掩码umask1.2 UMASK反掩码的作用1.2.1对于目录来说1.2.2对于文件来说 1.3如何修改UMASK反掩码1.4普通用户反掩码的测试 2.whereis的使用3. SUID权限弥补(主要针对文件,所有者执行位变…

第14章_数据结构与集合源码

第14章_数据结构与集合源码 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 1. 数据结构剖析 我们举一个形象的例子来理解数据结构的作用: 战场:程序运行…

认识Object类和深浅拷贝

本文介绍了Object类以及Object类部分方法,toString方法,equals和hashCode方法(重写前和重写后的对比),getClass方法,clone方法,以及拷贝新对象时会出现的深浅拷贝, 内容较长,耗时一天,建议收藏后观看~ Object类和深浅拷贝 一.初识Object类1.Object类接收所有子类实例2.Object类…

【C 字符串】02 常用字符串函数(命令行参数)

Navigator 一、strlen()函数—统计长度二、strcat()函数—拼接三、strncat()函数—strcat()的升级四、strcmp()和strncmp()—比较五、strcpy()和strncpy()—拷贝六、sprintf()函数—合并多个字符串七、其他可能用到的字符串函数八、ctype.h中的字符函数九、把字符串转换为数字十…

(03)基础强化:静态类静态成员,静态构造函数,抽象类抽象成员,值类型和引用类型,Ref

一、静态成员 1、方法重写注意事项 1)子类重写父类方法时,必须与父类保持一致的方法签名与返回值类型。即: 方 法名、返回值类型、参数列表都必须保持一致。[访问修饰符也得一致] 2)“方法签名”:一般是指…

VScode---visual stdio code快速安装教程(Windows系统)

1.下载VSCode安装包,官网传送门https://code.visualstudio.com/ 选择Windows下的User Installer 64 bit 直接下载速度如果很慢,在浏览器或者下载软件中就可以看到这么一个下载地址了,复制链接地址(如下图箭头所指)。 …

本节作业之5秒后自动关闭广告、倒计时、发送短信、5秒之后自动跳转页面、获取URL参数数据

本节作业之5秒后自动关闭广告、倒计时、发送短信、5秒之后自动跳转页面、获取URL参数数据 1 5秒后自动关闭广告2 倒计时3 发送短信4 5秒之后自动跳转页面5 获取URL参数数据 1 5秒后自动关闭广告 <!DOCTYPE html> <html lang"en"> <head><meta …

管理系统的前端模板(vue2+Element UI)

目录 前言 一、模板展示图 二、获取的方式及操作运行步骤 &#xff08;一&#xff09;获取方式 &#xff08;二&#xff09;操作步骤 1.下载安装node.js 2.下载完成解压缩后在idea的里面打开终端。 3.输入下载相关依赖的命令 4.运行项目的命令 5.然后把给到的地址…

腾讯云渲染实战

UE使用流渲染技术的主要原因是为了提高渲染效率和降低成本。流渲染技术可以将渲染任务分配到多个计算节点上进行并行处理&#xff0c;从而加快渲染速度。同时&#xff0c;流渲染技术还可以将渲染任务分配到云端进行处理&#xff0c;减少本地计算机的负担&#xff0c;降低成本。…

又一科研利器诞生!能对话的论文阅读器,hammerScholar

文&#xff5c;智商掉了一地 hammerScholar 新升级&#xff0c;用对话式读论文工具提升科研生产力~ 不得不说&#xff0c;自从 AIGC 这个概念出现以来&#xff0c;它极强的内容理解与生成能力也推动着各种生产力工具层出不穷&#xff0c;除了一些浏览器和代码插件以外&#xff…

SpringBoot的Interceptor拦截器的简介和实际使用

拦截器&#xff08;Interceptor&#xff09; 概念&#xff1a;是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。Spring框架中提供的&#xff0c;用来动态拦截控制器方法的执行。 作用&#xff1a;拦截请求&#xff0c;在指定的方法调用前后&#xff0c;根据业务需要执行…

干货 | 关于等效电路图

等效电路图是电路原理中非常重要的一个概念&#xff0c;在电子工程、通信工程和电力工程等领域中经常被使用。等效电路图是指将一个复杂的电路简化成一个简单的电路&#xff0c;同时保持电路的等效性质&#xff0c;以便于分析和设计电路。在本文中&#xff0c;我们将详细介绍等…