转:
这里讲述的是一个非常让人尴尬的故事
我们有一个简单的java类:
代码
- class Details {
- double getBalance();
- double getFixed();
- double getVariable();
- double getSpendDown();
- ...
-
- }
<script>render_code();</script>
现在业务逻辑需要对一些property做求和操作,求overallBalance, overallFixed之类的。
没什么了不起的,一个for循环分分钟搞定:
代码
- static double getOverallBalance(Details[] arr){
- double sum = 0;
- for(int i=0; i<arr.length; i++) {
- sum += arr[i].getBalance();
- }
- }
<script>render_code();</script>
同理,对overallFixed,代码大同小异,copy-paste先。
代码
- static double getOverallFixed(Details[] arr){
- double sum = 0;
- for(int i=0; i<arr.length; i++) {
- sum += arr[i].getFixed();
- }
- }
<script>render_code();</script>
这都没什么。可是当我写到第七个getOverallBlahBlah(arr)函数的时候,终于有点受不了了。这代码重复的虽然不多,但是架不住这么没完没了阿。
作为code-against-interface的推崇者,作为一个函数式编程的扇子,最自然的想法就是把不同的getter逻辑抽象成一个Getter接口,如下:
代码
- interface Getter {
- double get(Details details);
- }
- static double sum(Details[] arr, Getter getter){
- double sum = 0;
- for(int i=0; i<arr.length; i++) {
- sum += getter.get(arr[i]);
- }
- }
<script>render_code();</script>
娜爱思啊。有比这代码更优雅的么?
然后各个求和的代码变成:
代码
- double overallBalance = sum(details, new Getter(){
- public double get(Details details){
- return details.getBalance();
- }
- });
- double overallFixed = sum(details, new Getter(){
- public double get(Details details){
- return details.getFixed();
- }
- });
- ....
<script>render_code();</script>
嗯。几乎没有什么重复的逻辑了。
不过......
数数代码行数,怎么没有减少,反而略有盈余?仔细找找。发现原来的for loop是四行,现在的new Getter(){...}居然也是四行!!!
再加上一个sum()函数,我辛苦了半天的重构,居然代码行数增加了!
如果世界上有比一个java的匿名类的语法更臭的,那大概就是两个匿名类语法了。据说居然还有人质疑java 7引入closure语法的意义?
另一个方法是用apache commons beanutils的getProperty(),最终的语法会是:
代码
- double overallBalance = sum(details, "balance");
<script>render_code();</script>
语法足够简单了,但是重构的时候就麻烦了,也没有code-completion可用。
尴尬阿。这么一个简单的for loop,用匿名类重构似乎不值得。但是就任由这七个(也许回头还会更多)长得一模一样的for loop这么站在这气我?
走投无路,开始琢磨奇技淫巧了。
先声明一个接口,来包含所有需要sum的property getter。
代码
- private interface IDetails {
- double getBalance();
- double getFixed();
- double getVariable();
- double getSpendDown();
- ...
-
- }
<script>render_code();</script>
然后让Details实现IDetails。Details的代码不用变。
代码
- class Details implements IDetails {
- ...
-
- }
<script>render_code();</script>
戏肉来了。写一个dynamic proxy,来封装sum逻辑。
代码
- static IDetails sumOf(final IDetails[] arr){
- return (IDetails)Proxy.newProxyInstance(
- getClass().getClassLoader(), new Class[]{IDetails.class}, new InvocationHandler(){
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- double sum = 0;
- for(int i=0; i<arr.length; i++) {
- sum += ((Double)method.invoke(arr[i], args)).doubleValue();
- }
- return new Double(sum);
- }
- });
- }
<script>render_code();</script>
好了,接下来求sum的语法可以被简化为如下:
代码
- double overallBalance = sumOf(arr).getBalance();
- double overallFixed = sumOf(arr).getFixed();
- ...
<script>render_code();</script>
而且,再需要sum新的property,只需要把这个getter放进IDetails接口,就大功告成了。
很有趣的dynamic proxy应用。不过,一个求和这么简单的事情居然要动用这种奇技淫巧,很值得自豪么?
要是在ruby里,我就直接:
代码
<script>render_code();</script>
该死的java啊!
分享到:
相关推荐
通用分页方法接口的设计旨在提供一种标准化的、可复用的解决方案,使得不同的数据访问层(如数据库查询、API调用等)都能够方便地进行数据分页操作。下面我们将详细探讨这个主题。 一、分页的基本概念 分页是指将...
通用文件上传下载接口使用说明 通用文件上传下载接口使用说明是指在 JAVA 环境下的一种文件上传下载接口,主要提供文件上传、下载和删除三个主要功能。下面将对这三个主要功能进行详细的解释: 文件上传 文件上传...
"hibernate 通用接口架构"是指利用Hibernate框架,通过设计DAO(Data Access Object)层的接口来实现业务逻辑与数据访问的解耦,从而提高代码的可复用性和可维护性。 首先,我们来理解DAO层的作用。DAO层作为业务...
### 通用业务平台接口报文规范解析 #### 系统功能概述 《通用业务平台接口报文规范》是一份详尽的技术文档,旨在规范服务提供商与通用业务平台之间交互的标准和流程。该文档由上海新大陆翼码信息科技有限公司发布...
通用IDispatch接口是COM(Component Object Model)组件模型中的一个重要接口,主要用于支持晚绑定(late binding)和自动化(automation)。这个接口使得不熟悉组件具体类型的客户端代码能够动态地调用组件的方法和...
通用接口平台和数据转换方法是这些设备与上层软件系统交互的关键技术。让我们深入探讨这两个核心概念。 通用接口平台是一种设计用于连接多种不同物理装置的软件架构,它提供了标准化的通信方式,使得各种硬件设备...
北斗卫星导航系统用户终端通用数据接口协议(以下简称“北斗数据接口协议”),是一种规定了北斗卫星导航系统与用户终端之间数据交换的标准协议,适用于北斗卫星导航系统与应用研究。该协议主要包含北斗终端的硬件...
在这个场景下,"使用HttpClient调试android接口-通用方法"的标题表明我们将讨论如何使用HttpClient来调试Android应用中的API接口。下面,我们将深入探讨HttpClient的基础知识、调试技巧以及如何封装通用方法。 1. *...
通用文件上传下载接口使用说明提供了详细的文件上传和下载接口信息,包括请求方法、传输协议、请求数据格式和回应数据格式等,为开发者提供了一个明确的指南,帮助他们更好地使用文件上传下载接口。
要实现高效的数据库访问,一些比较通用的方法难以满足需求,开发人员不得不去学不同的数据库的特定的访问接口,如ORACLE/OCI,DB2/CLI等。本接口线已封装ORALCE的OCI和DB2的CLI,开发人员无须再学习这些复杂的接口。本...
【Unix下数据库的通用接口函数】是为了解决在Unix环境下,使用不同数据库开发方法(如ODBC、CLI、SQL内嵌C等)时,由于接口不统一导致的移植性差的问题。设计这套通用接口函数的目标是提高程序的通用性和开发效率,...
通用性接口通常是一个泛型接口(Generic Interface),例如 `<E>`,它定义了一组方法供客户端(Client)调用。这些接口可以是抽象的,如 `IE`,客户端通过接口调用 `operation()` 方法,实际执行的是实现了该接口的...
根据提供的文件内容,以下是对SUN2000逆变器南向接入跟踪系统通用MODBUS接口描述的知识点整理。 ### 文档信息 文档版本:03 发布日期:2016-10-21 版权所有:华为技术有限公司 适用产品:SUN2000逆变器 适用范围:...
本节详细定义了密码服务接口中各个函数的功能和使用方法,包括但不限于环境类函数、证书类函数、密码运算类函数以及消息类函数等。通过这些函数,开发者可以方便地调用底层的密码服务来完成各种密码操作。 #### 8. ...
"通用IO接口基本概念及连接方法" 本节课程涵盖了通用IO接口的基本概念、连接方法和应用场景。通用IO接口是微控制器与外界进行交互的重要通道,包括输入输出接口、人机交互接口、网络接口和机器设备接口等多种形式。...
【基本技巧:通用性设计方法】涉及到接口设计的基本概念和表述。接口设计包含了设计和表述两个步骤。架构师需要清晰地定义接口,确保其设计意图能准确传达给开发团队。EIT造形在其中起着桥梁作用,帮助架构师将抽象...
第三方通用登录接口使用说明 本文档将详细介绍第三方通用登录插件的使用说明,该插件支持QQ、人人网、微博、豆瓣等多种第三方登录方式,方便开发者快速实现第三方登录功能,减少开发时间和成本。 第三方登录插件...
本文档作为托利多电子秤开发手册的一部分,旨在详细介绍托利多通用电子秤动态链接库(Dynamic Link Library,简称DLL)的接口使用方法及其参数设置,以便开发者能够高效地与托利多电子秤进行通信。 #### 二、DLL...
例如,一个通用的数据加载接口可能包括`loadData()`、`saveData()`和`refreshData()`等方法,而每个具体的数据存储实现只需关注如何完成这些操作。 接口的设计还需要遵循一些最佳实践,例如: 1. **单一职责原则**...
"通用数据接口组件"是Delphi开发中非常重要的一部分,它允许开发者轻松地访问和操作各种数据源,如数据库、文件、网络等。这个组件集通常包括一系列预定义的类和函数,用于处理数据输入、输出和计算。 标题中的...