ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java 8 中的设计模式策略

2022-05-27 02:03:05  阅读:228  来源: 互联网

标签:Java 策略 valueOf Discounter amount 设计模式 我们 BigDecimal


概述

在本篇文章中我们对可以在 Java 8 中的设计模式策略(strategy design pattern)进行一些简单的说明。

如果你对 Java 的设计模式不是非常清楚的话,可以先自行脑补下。

我们简单的总结就是将以前 Java 使用的接口和实现的设计模式,在 Java 8 中可以使用 lambda 函数来进行简化。

在下面内容中,我们首先提供了一个简单的设计模式样例,以及在传统的环境下我们是怎么实现这个设计模式的。

 

boxi2

boxi2835×343 29.7 KB

 

随后,我们将会使用 Java 8 中的 lambda 函数来进行实现,然后介绍一些有什么不同的地方。

模式策略

所谓的模式策略(strategy pattern)的定义就是能够让我们的程序在运行时(runtime)改变算法的表现。

在通常的情况下,我们会首先设计一个接口,然后在这个接口中定义我们需要使用的方法,然后使用不同的类来实现我们的接口定义的方法。

这种设计模式为我们在 Java 面向对象设计时候经常用到的。

让我们来考察下面的一个使用案例,针对不同的节日,我们针对某一个销售使用不同的定价策略,比如说圣诞节(Christmas),复活节(Easter)或者新年(New Year),我们使用的价格策略是不一样的。

首先我们需要在接口中定义一个 Discounter 方法,然后针对不同的节日来实现 Discounter 这个方法。

public interface Discounter {
    BigDecimal applyDiscount(BigDecimal amount);
}

然后我们的目标是在复活节的时候打 5 折(50%),另外一个目标是在圣诞节的时候打 9 折(10%)。

随后我们就可以在下面的 2 个类中实现我们在接口中定义的方法。

public static class EasterDiscounter implements Discounter {
    @Override
    public BigDecimal applyDiscount(final BigDecimal amount) {
        return amount.multiply(BigDecimal.valueOf(0.5));
    }
}

public static class ChristmasDiscounter implements Discounter {
   @Override
   public BigDecimal applyDiscount(final BigDecimal amount) {
       return amount.multiply(BigDecimal.valueOf(0.9));
   }
}

然后,我们在则是中使用这个策略:

Discounter easterDiscounter = new EasterDiscounter();

BigDecimal discountedValue = easterDiscounter
  .applyDiscount(BigDecimal.valueOf(100));

assertThat(discountedValue)
  .isEqualByComparingTo(BigDecimal.valueOf(50));

上面这个设计模式是我们在通常情况下使用的,但是比较头痛的是针对每一个方法,你需要在实现中都实现你需要的方法。

另外一个解决方案就是使用内部类型,但是这个内部类型并没有有太多的提高,你还是有不少的工作需要做。

例如下面使用内部类型的实现:

Discounter easterDiscounter = new Discounter() {
    @Override
    public BigDecimal applyDiscount(final BigDecimal amount) {
        return amount.multiply(BigDecimal.valueOf(0.5));
    }
};

使用 Java 8

如果你开始使用 Java 8 的话,我们知道 lambda 函数表达式可以做内部类型来使用,这样能够明显的降低多余的代码。

同时会让我们的代码看起来更加整洁和可读。

不管怎么样,使用 lambda 表达是提供了另外一种模式的实现,针对最开始的实现来说,Java 8 的实现提供了更多的一种选择。

降低代码的冗余

现在我们针对 EasterDiscounter 的实现,我们现在只是用 lambda 表达式来实现:

Discounter easterDiscounter = amount -> amount.multiply(BigDecimal.valueOf(0.5));

通过上面的代码,我们可以看到使用 lambda 表达式的实现看起来更加整洁,代码更加可读和便于维护,针对开始使用多行才能实现的内容,现在只需要使用一行就可以完成了。

更主要的是: ** 一个 lambda 表达式可以被用来替换匿名的内部类型**。

如果我们需要对多个折扣力度进行实现的话,使用 lambda 表达式就看起来更加漂亮了:

List<Discounter> discounters = newArrayList(
  amount -> amount.multiply(BigDecimal.valueOf(0.9)),
  amount -> amount.multiply(BigDecimal.valueOf(0.8)),
  amount -> amount.multiply(BigDecimal.valueOf(0.5))
);

如果我们需要对很多折扣力度进行定义的话,我们可以在 Java 8 中使用静态方法,然后这个定义将会在一个类中完成。

如果你愿意的话,Java 8 甚至可以让你在接口中定义静态方法。

对比在实体类和匿名内部类型之间进行选择,让我们在一个单独类中创建多个静态 lambda 表达式:

public interface Discounter {
    BigDecimal applyDiscount(BigDecimal amount);

    static Discounter christmasDiscounter() {
        return amount -> amount.multiply(BigDecimal.valueOf(0.9));
    }

    static Discounter newYearDiscounter() {
        return amount -> amount.multiply(BigDecimal.valueOf(0.8));
    }

    static Discounter easterDiscounter() {
        return amount -> amount.multiply(BigDecimal.valueOf(0.5));
    }
}

通过上面的代码,我们可以看到使用了较少的代码,我们实现了很多的功能。

改进方法的创建

让我们来对 Discounter 接口再次进行修改,这次我们让 Discounter 接口继承 UnaryOperator 接口,然后添加一 combine() 方法:

public interface Discounter extends UnaryOperator<BigDecimal> {
    default Discounter combine(Discounter after) {
        return value -> after.apply(this.apply(value));
    }
}

最开始的设计就是通过对 Discounter 接口的调整,能够让 Discounter 接口能够对折扣进行处理。

随着 UnaryOperator 接口被继承,我们可以使用 UnaryOperator 接口提供的 apply() 方法,我们只需要对 applyDiscount 进行替换就可以了。

combine() 方法为在 Discounter 接口中应用的一个抽象,使用一个内建的 apply() 函数来实现。

现在,让我们来试试针对某一个价格实现多折扣的情况,我们将会使用 reduce() 和我们的 combine() 函数来实现:

Discounter combinedDiscounter = discounters
  .stream()
  .reduce(v -> v, Discounter::combine);

combinedDiscounter.apply(...);

特别关注下 reduce 的第一参数,如果我们没有任何折扣被使用,我们需要返回一个没有修改的值。

当然你也可以在这里定义一个函数,通过这个定义的函数来实现一个默认的折扣。

2022-05-26_12-52-03

针对默认的遍历选项来说,通过这种实现为我们提供了更多的函数功能。

结论

在本代码中,我们对 Java 8 中的设计模式策略(strategy design pattern)进行一些简单的说明,因为 lambda 表达式的使用,让我们能够使用更少的代码实现更多的功能。

如果你觉得这篇文章有点难度的话,你需要先对 Java 的一些面向对象设计有所了解,对接口,抽象,继承,内部类型等都需要有些熟悉才能更好的理解。

 

https://www.ossez.com/t/java-8/13978

标签:Java,策略,valueOf,Discounter,amount,设计模式,我们,BigDecimal
来源: https://www.cnblogs.com/huyuchengus/p/16316027.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有