java模板/策略模式打怪兽

简介: 一起打坏兽有个记者去光之国采访一群奥特曼,他问迪迦奥特曼:“你每天都干什么?”迪迦奥特曼说:“训练,飞翔,用光线打怪兽!”接着又问戴拿奥特曼,戴拿奥特曼说:“训练,飞翔,用体术打怪兽!”记者带着困惑问其他的奥特曼,答案都一样,就这样一直问了 99 个奥特曼。当走到第 100 个奥特曼旁边时,记者走过去问他:每天都做些什么啊?第100个奥特曼回答:"训练,飞翔."记者惊奇的又问:"你怎么不打怪兽?"那名奥特曼撇着嘴巴,瞪了记者一眼说:"我就是怪兽,我的名字就是怪兽!" 啊,原来是"怪兽奥特曼";

模板&策略模式
实现姿势
我们会从简单到复杂,讲解代码正确的实现姿势,分别为最 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();
}

}

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

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

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();
}

}

测试结果:
image.png

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

这 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());
}

}
测试结果:
image.png

策略模式
定义:一个类的行为或其算法可以在运行时更改,即我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 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();
}

}
执行结果:
image.png
我们可以通过给 behaviorContext 传递不同的策略对象,然后来约定 everyDo() 的调用方式。

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

相似:

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

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

差异:

策略模式:

它基于接口;

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

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

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

绑定是在编译时完成的。

模板模式:

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

模块耦合得更紧密;

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

它用于在 algorithm 族之间切换;

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

绑定在运行时完成

相关文章
|
14天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
25 6
|
27天前
|
算法 Java Linux
java制作海报四:java BufferedImage 转 InputStream 上传至OSS。png 图片合成到模板(另一个图片)上时,透明部分变成了黑色
这篇文章主要介绍了如何将Java中的BufferedImage对象转换为InputStream以上传至OSS,并解决了png图片合成时透明部分变黑的问题。
46 1
|
1月前
|
Java
Java PDF模板生成PDF
Java PDF模板生成PDF
30 1
|
6月前
|
设计模式 算法 Java
Java中的策略模式
Java中的策略模式
49 1
|
6月前
|
存储 Java
Dijkstra最短路径(Java)(详细+模板)
Dijkstra最短路径(Java)(详细+模板)
51 4
|
6月前
|
设计模式 算法 Java
Java一分钟之-设计模式:策略模式与模板方法
【5月更文挑战第17天】本文介绍了策略模式和模板方法模式,两种行为设计模式用于处理算法变化和代码复用。策略模式封装不同算法,允许客户独立于具体策略进行选择,但需注意选择复杂度和过度设计。模板方法模式定义算法骨架,延迟部分步骤给子类实现,但过度抽象或滥用继承可能导致问题。代码示例展示了两种模式的应用。根据场景选择合适模式,以保持代码清晰和可维护。
109 1
|
2月前
|
设计模式 运维 算法
Java设计模式-策略模式(15)
Java设计模式-策略模式(15)
|
1月前
|
小程序
java--微信小程序发送模板消息
java--微信小程序发送模板消息
92 0
|
3月前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
62 2
|
3月前
|
小程序 Java
【aspose-words】Aspose.Words for Java模板语法详细剖析
本文通过详细分析Aspose.Words for Java模板语法,介绍了使用条件块、变量和动态合并表格单元格三个常用模板标签,并结合实际案例进行演示。通过这三个标签的实操,帮助读者更好地掌握Aspose.Words的使用技巧。此外,还提供了官方文档链接以便进一步学习。
134 0
【aspose-words】Aspose.Words for Java模板语法详细剖析