文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring中如何使用设计模式

2023-06-05 05:14

关注

关于设计模式,如果使用得当,将会使我们的代码更加简洁,并且更具扩展性。本文主要讲解Spring中如何使用策略模式,工厂方法模式以及Builder模式。

1. 策略模式

关于策略模式的使用方式,在Spring中其实比较简单,从本质上讲,策略模式就是一个接口下有多个实现类,而每种实现类会处理某一种情况。我们以发奖励为例进行讲解,比如我们在抽奖系统中,有多种奖励方式可供选择,比如积分,虚拟币和现金等。在存储时,我们必然会使用一个类似于type的字段用于表征这几种发放奖励的,那么这里我们就可以使用多态的方式进行奖励的发放。比如我们抽象出一个PrizeSender的接口,其声明如下:

public interface PrizeSender {    boolean support(SendPrizeRequest request);    void sendPrize(SendPrizeRequest request);}

该接口中主要有两个方法:support()和sendPrize(),其中support()方法主要用于判断各个子类是否支持当前类型数据的处理,而sendPrize()则主要是用于进行具体的业务处理的,比如这里奖励的发放。下面就是我们三种不同类型的奖励发放的具体代码:

// 积分发放@Componentpublic class PointSender implements PrizeSender {  @Override  public boolean support(SendPrizeRequest request) {    return request.getPrizeType() == PrizeTypeEnum.POINT;  }  @Override  public void sendPrize(SendPrizeRequest request) {    System.out.println("发放积分");  }}
// 虚拟币发放@Componentpublic class VirtualCurrencySender implements PrizeSender {  @Override  public boolean support(SendPrizeRequest request) {    return PrizeTypeEnum.VIRTUAL_CURRENCY == request.getPrizeType();  }  @Override  public void sendPrize(SendPrizeRequest request) {    System.out.println("发放虚拟币");  }}
// 现金发放@Componentpublic class CashSender implements PrizeSender {  @Override  public boolean support(SendPrizeRequest request) {    return PrizeTypeEnum.CASH == request.getPrizeType();  }  @Override  public void sendPrize(SendPrizeRequest request) {    System.out.println("发放现金");  }}

这里可以看到,在每种子类型中,我们只需要在support()方法中通过request的某个参数来控制当前request是否是当前实例能够处理的类型,如果是,则外层的控制逻辑就会将request交给当前实例进行处理。关于这个类的设计,有几个点需要注意:

2. 工厂方法模式

上面我们讲解了如何使用Spring来声明一个策略模式,那么如何为不同的业务逻辑来注入不同的bean呢,或者说外层的控制逻辑是什么样的,这里我们就可以使用工厂方法模式了。所谓的工厂方法模式,就是定义一个工厂方法,通过传入的参数,返回某个实例,然后通过该实例来处理后续的业务逻辑。一般的,工厂方法的返回值类型是一个接口类型,而选择具体子类实例的逻辑则封装到了工厂方法中了。通过这种方式,来将外层调用逻辑与具体的子类的获取逻辑进行分离。如下图展示了工厂方法模式的一个示意图:

Spring中如何使用设计模式

可以看到,工厂方法将具体实例的选择进行了封装,而客户端,也就是我们的调用方只需要调用工厂的具体方法获取到具体的事例即可,而不需要管具体的实例实现是什么。上面我们讲解了Spring中是如何使用策略模式声明处理逻辑的,而没有讲如何选择具体的策略,这里我们就可以使用工厂方法模式。如下是我们声明的一个PrizeSenderFactory:

@Componentpublic class PrizeSenderFactory {  @Autowired  private List<PrizeSender> prizeSenders;  public PrizeSender getPrizeSender(SendPrizeRequest request) {    for (PrizeSender prizeSender : prizeSenders) {      if (prizeSender.support(request)) {        return prizeSender;      }    }    throw new UnsupportedOperationException("unsupported request: " + request);  }}

这里我们声明一个了一个工厂方法getPrizeSender(),其入参就是SendPrizeRequest,而返回值是某个实现了PrizeSender接口的实例,可以看到,通过这种方式,我们将具体的选择方式下移到了具体的子类中的,因为当前实现了PrizeSender的bean是否支持当前request的处理,是由具体的子类实现的。在该工厂方法中,我们也没有任何与具体子类相关的逻辑,也就是说,该类实际上是可以动态检测新加入的子类实例的。这主要是通过Spring的自动注入来实现的,主要是因为我们这里注入的是一个List<PrizeSender>,也就是说,如果有新的PrizeSender的子类实例,只要其是Spring所管理的,那么都会被注入到这里来。下面就是我们编写的一段用于测试的代码来模拟调用方的调用:

@Servicepublic class ApplicationService {  @Autowired  private PrizeSenderFactory prizeSenderFactory;  public void mockedClient() {    SendPrizeRequest request = new SendPrizeRequest();    request.setPrizeType(PrizeTypeEnum.POINT);  // 这里的request一般是根据数据库或外部调用来生成的    PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request);    prizeSender.sendPrize(request);  }}

在客户端代码中,首先通过PrizeSenderFactory获取一个PrizeSender实例,然后通过其sendPrize()方法发放具体的奖励,通过这种方式,将具体的奖励发放逻辑与客户端调用进行了解耦。而且根据前面的讲解,我们也知道,如果新增了一种奖励方式,我们只需要声明一个新的实现了PrizeSender的bean即可,而不需要对现有代码进行任何修改。

3. Builder模式

关于Builder模式,我想使用过lombok的同学肯定会说builder模式非常的简单,只需要在某个bean上使用@Builder注解进行声明即可,lombok可以自动帮我们将其声明为一个Builder的bean。关于这种使用方式,本人不置可否,不过就我的理解,这里主要有两个点我们需要理解:

关于Builder模式,我们可以以前面奖励发放的SendPrizeRequest的构造为例进行讲解。在构造request对象的时候,必然是通过前台传如的某些参数来经过一定的处理,最后生成一个request对象。那么我们就可以使用Builder模式来构建一个SendPrizeRequest。这里假设根据前台调用,我们能够获取到prizeId和userId,那么我们就可以创建一个如下的SendPrizeRequest:

public class SendPrizeRequest {  private final PrizeTypeEnum prizeType;  private final int amount;  private final String userId;  public SendPrizeRequest(PrizeTypeEnum prizeType, int amount, String userId) {    this.prizeType = prizeType;    this.amount = amount;    this.userId = userId;  }  @Component  @Scope("prototype")  public static class Builder {    @Autowired    PrizeService prizeService;    private int prizeId;    private String userId;    public Builder prizeId(int prizeId) {      this.prizeId = prizeId;      return this;    }    public Builder userId(String userId) {      this.userId = userId;      return this;    }    public SendPrizeRequest build() {      Prize prize = prizeService.findById(prizeId);      return new SendPrizeRequest(prize.getPrizeType(), prize.getAmount(), userId);    }  }  public PrizeTypeEnum getPrizeType() {    return prizeType;  }  public int getAmount() {    return amount;  }  public String getUserId() {    return userId;  }}

这里就是使用Spring维护一个Builder模式的示例,具体的 维护方式就是在Builder类上使用@Component和@Scope注解来标注该Builder类,这样我们就可以在Builder类中注入我们所需要的实例来进行一定的业务处理了。关于该模式,这里有几点需要说明:

上面我们展示了如何使用Spring的方式来声明一个Builder模式的类,那么我们该如何进行使用呢,如下是我们的一个使用示例:

@Servicepublic class ApplicationService {  @Autowired  private PrizeSenderFactory prizeSenderFactory;  @Autowired  private ApplicationContext context;  public void mockedClient() {    SendPrizeRequest request = newPrizeSendRequestBuilder()        .prizeId(1)        .userId("u4352234")        .build();    PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request);    prizeSender.sendPrize(request);  }  public Builder newPrizeSendRequestBuilder() {    return context.getBean(Builder.class);  }}

上述代码中,我们主要要看一下newPrizeSendRequestBuilder()方法,在Spring中,如果一个类是多例类型,也即使用@Scope("prototype")进行了标注,那么每次获取该bean的时候就必须使用ApplicationContext.getBean()方法获取一个新的实例,至于具体的原因,读者可查阅相关文档。我们这里就是通过一个单独的方法来创建一个Builder对象,然后通过流式来为其设置prizeId和userId等参数,最后通过build()方法构建得到了一个SendPrizeRequest实例,通过该实例来进行后续的奖励发放。

4. 小结

本文主要通过一个奖励发放的示例来对Spring中如何使用工厂方法模式,策略模式和Builder模式的方式进行讲解,并且着重强调了实现各个模式时我们所需要注意的点。



阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯