Java 8函数式编程模式:使用枚举的方法

栏目: Java · 发布时间: 5年前

内容简介:假设有三种电影类型,每种类型都有自己的计算公式,该公式是根据借出的天数计算价格:测试:结果:

假设有三种电影类型,每种类型都有自己的计算公式,该公式是根据借出的天数计算价格:

<b>class</b> Movie {
        enum Type {
                REGULAR, NEW_RELEASE, CHILDREN
        }
        <b>private</b> <b>final</b> Type type;
        <b>public</b> Movie(Type type) {
                <b>this</b>.type = type;
        }
        <b>public</b> <b>int</b> computePrice(<b>int</b> days) {
                <b>switch</b> (type) {
                <b>case</b> REGULAR: <b>return</b> days + 1;
                <b>case</b> NEW_RELEASE: <b>return</b> days * 2;
                <b>case</b> CHILDREN: <b>return</b> 5;
                <b>default</b>: <b>throw</b> <b>new</b> IllegalArgumentException(); <font><i>// Always have this here!</i></font><font>
                }
        }
}
</font>

测试:

System.out.println(<b>new</b> Movie(Movie.Type.REGULAR).computePrice(2));
System.out.println(<b>new</b> Movie(Movie.Type.NEW_RELEASE).computePrice(2));
System.out.println(<b>new</b> Movie(Movie.Type.CHILDREN).computePrice(2));

结果:

3

4

5

上面代码中的问题可能是switch:无论何时向枚举添加新值,都需要搜索所有开关并确保处理新情况。

但这很脆弱。会弹出IllegalArgumentException,简而言之,虽然任何人都可以阅读此代码,但它有点冒险。

避免风险的一种方法是OOP解决方案:

<b>abstract</b> <b>class</b> Movie {
        <b>public</b> <b>abstract</b> <b>int</b> computePrice(<b>int</b> days);
}
<b>class</b> RegularMovie <b>extends</b> Movie {
        <b>public</b> <b>int</b> computePrice(<b>int</b> days) {
                <b>return</b> days+1;
        }
}
<b>class</b> NewReleaseMovie <b>extends</b> Movie {
        <b>public</b> <b>int</b> computePrice(<b>int</b> days) {
                <b>return</b> days*2;
        }
}
<b>class</b> ChildrenMovie <b>extends</b> Movie {
        <b>public</b> <b>int</b> computePrice(<b>int</b> days) {
                <b>return</b> 5;
        }
}

如果您创建一种新类型的影片,实际上是一个新的子类,但是继承问题来了,如果你想按照另一个标准对电影进行分类,比如发行年份怎么办?或者几个月后你会如何处理从电影Type.NEW_RELEASE到Type.REGULAR电影的“降级” ?

让我们寻找其他方法来实现它,使用枚举抽象方法实现此逻辑。

这里如果直接提出更改需求:“ 公式中的因子:新发行电影的价格(在我们的示例中为2)必须通过数据库更新。”

这意味着我必须从一些注入的存储库中获取此因子。但是,由于我不能在我的Movie实体中注入repos ,让我们将逻辑移到一个单独的类中:

<b>public</b> <b>class</b> PriceService {
        <b>private</b> <b>final</b> NewReleasePriceRepo repo;
        <b>public</b> PriceService(NewReleasePriceRepo repo) {
                <b>this</b>.repo = repo;
        }
        <b>public</b> <b>int</b> computeNewReleasePrice(<b>int</b> days) {
                <b>return</b> (<b>int</b>) (days * repo.getFactor());
        }
        <b>public</b> <b>int</b> computeRegularPrice(<b>int</b> days) {
                <b>return</b> days + 1;
        }
        <b>public</b> <b>int</b> computeChildrenPrice(<b>int</b> days) {
                <b>return</b> 5;
        }
        <b>public</b> <b>int</b> computePrice(Movie.Type type, <b>int</b> days) {
                <b>switch</b> (type) {
                <b>case</b> REGULAR: <b>return</b> computeRegularPrice(days);
                <b>case</b> NEW_RELEASE: <b>return</b> computeNewReleasePrice(days);
                <b>case</b> CHILDREN: <b>return</b> computeChildrenPrice(days);
                <b>default</b>: thrownew IllegalArgumentException();
                }
        }
}

switch又回来聊,带来了固有的风险

<b>public</b> <b>class</b> Movie { 
       <b>public</b> enum Type {
              REGULAR(PriceService::computeRegularPrice),
              NEW_RELEASE(PriceService::computeNewReleasePrice),
              CHILDREN(PriceService::computeChildrenPrice);
              <b>public</b> <b>final</b> BiFunction<PriceService, Integer, Integer> priceAlgo;
              <b>private</b> Type(BiFunction<PriceService, Integer, Integer> priceAlgo) {
                     <b>this</b>.priceAlgo = priceAlgo;
              }
       }
       ...
}

我在每个枚举值中存储一个方法引用到相应的实例方法PriceService.

这样不需要switch:

<b>class</b> PriceService {
       ...
       <b>public</b> <b>int</b> computePrice(Movie.Type type, <b>int</b> days) {
              <b>return</b> type.priceAlgo.apply(<b>this</b>, days);
       }
}

于我以静态方式(from PriceService::)引用实例方法,因此我需要PriceService在调用时提供实例作为第一个参数,这里使用了this,这样,我可以从枚举值定义的静态上下文中有效地引用任何[Spring] bean的方法。

您可以使用方法引用将类型特定的逻辑挂钩到枚举,以确保每个枚举值与相应的逻辑位相关联。


以上所述就是小编给大家介绍的《Java 8函数式编程模式:使用枚举的方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

领域驱动设计

领域驱动设计

[美] Eric Evans / 赵俐、盛海艳、刘霞 / 人民邮电出版社 / 2016-6-1 / 69

本书是领域驱动设计方面的经典之作,修订版更是对之前出版的中文版进行了全面的修订和完善。 全书围绕着设计和开发实践,结合若干真实的项目案例,向读者阐述如何在真实的软件开发中应用领域驱动设计。书中给出了领域驱动设计的系统化方法,并将人们普遍接受的一些实践综合到一起,融入了作者的见解和经验,展现了一些可扩展的设计新实践、已验证过的技术以及便于应对复杂领域的软件项目开发的基本原则。一起来看看 《领域驱动设计》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具