Java设计模式——策略模式(解决满屏的if/else)

一、业务场景

项目需要对接支付系统,根据不同客户类型会有不同的支付方式,比如:支付宝、微信、银联、云闪付等等其他第三方支付平台,这个时候策略模式就大展身手了。

传统的if/else/switch 等等判断的写法太low了,代码糅合在一块,维护也不方便。

二、简单代码示例

1、实体类准备

订单信息类

package com.iot.designpattern.strategy.model;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 订单信息
 *
 * @author Mr.Qu
 * @since 2021/5/18 10:56
 */
@Data
@Accessors(chain = true)
public class Order {
    /**
     * 金额
     */
    private int amount;

    /**
     * 支付类型
     */
    private String type;
}

返回结果类

package com.iot.designpattern.strategy.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 支付结果
 *
 * @author Mr.Qu
 * @since 2021/5/18 10:59
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PayResult {
    /**
     * 响应码
     */
    private int code;
    /**
     * 提示信息
     */
    private String msg;

    public static PayResult success(String msg) {
        return new PayResult(200, msg);
    }
}

2、定义策略接口(所有支付方式的接口),策略接口如下:

package com.iot.designpattern.strategy.service;

import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;

/**
 * 支付接口
 *
 * @author Mr.Qu
 * @since 2021/5/18 10:52
 */
public interface IPayment {

    /**
     * 支付
     *
     * @param order 订单信息
     * @return PayResult 支付结果
     */
    PayResult pay(Order order);
}

3、定义各种策略实现类

支付宝支付实现类:

package com.iot.designpattern.strategy.service.Impl;

import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import org.springframework.stereotype.Service;

/**
 * 支付宝支付
 *
 * @author Mr.Qu
 * @since 2021/5/18 11:08
 */
@Service
public class AliPay implements IPayment {
    @Override
    public PayResult pay(Order order) {
        return new PayResult(200, "支付宝支付成功");
    }
}

微信支付实现类:

package com.iot.designpattern.strategy.service.Impl;

import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import org.springframework.stereotype.Service;

/**
 * 微信支付
 *
 * @author Mr.Qu
 * @since 2021/5/18 10:58
 */
@Service
public class WechatPay implements IPayment {

    @Override
    public PayResult pay(Order order) {
        return new PayResult(200, "微信支付成功");
    }
}

银联支付实现类:

package com.iot.designpattern.strategy.service.Impl;

import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import org.springframework.stereotype.Service;

/**
 * 银联支付
 *
 * @author Mr.Qu
 * @since 2021/5/18 11:10
 */
@Service
public class UnionPay implements IPayment {
    @Override
    public PayResult pay(Order order) {
        System.out.println("开始银联支付");
        return PayResult.success("银联支付成功");
    }
}

注:通过@Service注解将支付实现类注入spring工厂管理,默认bean名字是类名(开头小写)

4、使用策略

package com.iot.designpattern.strategy.controller;

import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 支付
 *
 * @author Mr.Qu
 * @since 2021/5/18 15:30
 */
@RestController
@AllArgsConstructor
@RequestMapping("/pay/")
public class PayController {

    private final ApplicationContext applicationContext;

    /**
     * 支付API
     *
     * @param amount  金额
     * @param payType 支付类型
     * @return PayResult
     */
    @GetMapping()
    public PayResult pay(int amount, String payType) {
        Order order = new Order().setAmount(amount).setType(payType);

        //  根据【支付类型】获取对应的策略 bean
        IPayment payment = applicationContext.getBean(payType, IPayment.class);

        //  开始调用策略对应的支付业务逻辑
        return payment.pay(order);
    }
}

5、测试一下:

注:在调用的时候,注意payType中值为@Service对应的类名(开头小写),也可以自己在注解中命名name

三、总结

使用策略模式,我们可以干掉大量的if/else,代码也更优雅,还能灵活扩展。像本文中的支付案例,后面如果有别的支付方式,我们只需要写一个新的对应支付实现类即可,无需修改现有代码。

当然,完全干掉if/else是不可能的,不能过度设计,不能为了使用设计模式而使用设计模式。

策略模式的优点:

  1. 干掉繁琐的if、switch判断逻辑;
  2. 代码优雅、可服用、可读性好;
  3. 符合开闭原则、扩展性好、便于维护;

策略模式的缺点:

  1. 策略如果很多的话,会造成策略类膨胀;
  2. 使用者必须清楚所有的策略类及其用途;

### 实现俄罗斯方块的行消除与得分逻辑 在俄罗斯方块游戏中,行消除和得分计算是非常重要的部分。以下是详细的实现方法: #### 行消除逻辑 为了检测并清除已填满的行,可以在每次动态方块停止移动后调用一个检查函数。具体步骤如下: 1. 遍历整个网格数组 `grid` 的每一行。 2. 如果某一行的所有单元格都被填充,则标记该行为可删除。 3. 将被标记的行上方的所有行向下平移一位。 4. 使用空白行填补顶部。 下面是具体的代码实现: ```java public boolean checkLines() { int clearedLines = 0; for (int row = HEIGHT - 1; row >= 0; row--) { boolean isFull = true; for (int col = 0; col < WIDTH; col++) { if (grid[row][col] == 0) { // 判断当前单元格是否为空 isFull = false; break; } } if (isFull) { // 当前行已被完全填充 clearLine(row); clearedLines++; row++; // 因为上面的行会下降,所以需要重新检查这一行 } } updateScore(clearedLines); // 更新分数 return clearedLines > 0; } private void clearLine(int row) { for (int r = row; r > 0; r--) { System.arraycopy(grid[r - 1], 0, grid[r], 0, WIDTH); // 上面的行覆盖当前行 } Arrays.fill(grid[0], 0); // 填充最顶行为空 } ``` 此段代码实现了对每行的遍历以及清理操作,并通过 `updateScore()` 方法更新玩家得分[^1]。 --- #### 得分计算逻辑 当成功消除一行或多行时,应根据所消除的行数给予不同的奖励。常见的得分配比如下表所示: | 消除行数 | 得分 | |----------|------| | 1 | 100 | | 2 | 300 | | 3 | 600 | | 4 | 1000 | 可以通过以下方式实现得分更新功能: ```java private int score = 0; public void updateScore(int linesCleared) { switch (linesCleared) { case 1 -> this.score += 100; case 2 -> this.score += 300; case 3 -> this.score += 600; case 4 -> this.score += 1000; default -> {} // 不做任何处理 } repaint(); // 调用重绘界面以显示最新分数 } // 绘制分数到屏幕上 @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.setColor(Color.WHITE); g2d.drawString("Score: " + score, 10, 20); // 显示分数位置可以根据需求调整 g2d.dispose(); drawGrid(g); // 绘制游戏区域 } ``` 上述代码片段展示了如何基于消除的行数增加分数,并将其渲染至屏幕上的指定位置[^2]。 --- #### 完整流程整合 最后,在主循环或事件触发机制中加入这些逻辑。例如,在定时器回调函数或者按键响应函数中执行以下操作: ```java if (!currentTetromino.moveDown()) { // 动态方块无法再向下方移动 currentTetromino.lockInPlace(grid); // 锁定当前位置 if (checkLines()) { // 检查是否有行可以消除 spawnTetromino(); // 生产新的动态方块 } else { gameOver(); // 若无空间生成新方块,则结束游戏 } } repaint(); // 重绘界面 ``` 这段代码确保了每当一个动态方块到达底部时都会尝试锁定其位置、检查是否存在可消除的行,并最终刷新画面[^3]。 --- ### 总结 通过以上设计模式和技术手段,能够有效地完成俄罗斯方块中的核心玩法——行消除与得分统计的功能开发工作。希望这份解答对你有所帮助!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.Qubb

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值