这个故事我早就想说了,可能是在好多个月前,只是一直不知道怎么说才能说合适,现在我重新整理了一下,讲述给大家。
这个故事是从下面这样一个对外暴露接口的调用开始的。
QueryUserEvent event = new QueryUserEvent();
event.setName(name);
event.setAge(18);
event.setType(QueryUserEvent.TYPE_NORMAL);
event.setSex(QueryUserEvent.SEX_MALE);
……
List<User> userList = userService.query(event);
我想做的事情其实很简单,我想查询一个用户列表,可是接口参数的拼装让我感到头疼,这样的代码太过啰嗦,我希望有可读性更好的解决办法。
P兄台说,如果我直接传入一个user对象,是不是可以避开了这个未必带来多少好处的event?
User user = new User();
user.setName(name);
user.setAge(18);
user.setSex(QueryUserEvent.SEX_MALE);
……
List<User> userList = userService.query(user, UserService.QUERY_TYPE_NORMAL);
我有时候会考虑你说的办法的,可是,你没有解决实际的问题,我现在的最大问题在于,这一堆的setXXX方法,它破坏了我构造这个查询条件对象的流畅性。
他紧接着说,那要不然,我们把setXXX方法的劳动省下来,让构造器来替我们完成这个任务吧:
User user = new User(name, 18, QueryUserEvent.SEX_MALE, ……);
List<User> userList = userService.query(user, UserService.QUERY_TYPE_NORMAL);
我说,你的办法看起来不错,不过有时候按你的办法做,我的构造方法会变得臃肿无比,比如出现十多个参数;
另外还有一个问题,假如说,我的查询条件是简单的(我只需要根据年龄查询),那么其它的参数都要写成null,类似这样子:
User user = new User(null, 18, null, null, null, null, ……);
List<User> userList = userService.query(user, UserService.QUERY_TYPE_NORMAL);
天,让谁去阅读这样的代码,他都不会喜欢的。
而且,有时候情形变得复杂,比如,我不是要查询18岁的所有user,而是要查询大于18岁的所有user,你的办法似乎行不通了呢……
你真是一个麻烦的人,他说,这样吧,我定义一个Condition,他给查询条件带来了灵活的组装方式:
UserQueryCondition condition = new UserQueryCondition();
condition.setAge(Condition.GREATER_THAN, 18);
List<User> userList = userService.query(condition, UserService.QUERY_TYPE_NORMAL);
不过,他补充道,如果在JavaScript中,我可以采取的办法要好得多。如果要查询18岁的和符合其他条件的用户,可以这样写:
userService.query({
name : name,
age : 18,
sex : User.SEX_MALE
}, UserService.QUERY_TYPE_NORMAL);
如果要大于18岁呢,可以这样写:
userService.query({
name : name,
greaterThan : {
age : 18
},
sex : User.SEX_MALE
}, UserService.QUERY_TYPE_NORMAL);
不过,他接着说,在Java里面好像还没有类似简洁的表示方法……
万幸的是,有一种接口连续调用的风格,叫做“Fluent Interface”,可以让这个问题写成这样一种有趣的实现:
List<User> userList = new UserService().setName(name).setAge(18).setSex(User.SEX_MALE).query(UserService.QUERY_TYPE_NORMAL);
大于18岁的话,这样写:
List<User> userList = new UserService().setName(name).greaterThan(new User().setAge(18)).setSex(User.SEX_MALE).query(UserService.QUERY_TYPE_NORMAL);
我想,这样的设计如果在数学计算的时候,会显得有用得多,看这样一个算式:
ln(sin((x+y)的平方))
如果用传统的方式来实现的话,应该类似这样子:
Math.log(Math.sin(Math.sqrt(x + y)))
显然,它的可读性不如Fluent Interface来得好:
new MyNumber(x+y).sqrt().sin().log()
这样的例子还有很多,比如在JQuery中的使用,在EasyMock中的使用等等。看下面的例子,这样构建一个DOM树,是不是比单纯的字符串拼接,要好理解一些呢?
$("#div1")
.div({id:"subDIV"})
.h1("A Title")
.a({href:"xxx"})
.a()
.h1()
.div();
《CommandQuerySeperation》这篇文章把一个对象的方法大致分成下面两种:
Queries: Return a result and do not change the observable state of the system (are free of side effects).
Commands: Change the state of a system but do not return a value.
对于Fluent Interface而言,它的接口调用既改变了对象的状态,又返回了对象(this或其他),并不属于上面的两种类型。
文章系本人原创,转载请注明出处和作者
分享到:
相关推荐
这种接口设计风格使得代码看起来更像是自然语言,增强了代码的可读性和可维护性。在Java编程语言中,Fluent Interface常通过方法链来实现,即一个方法的返回值是当前对象本身,这样可以连续调用多个方法而无需创建新...
Fluent API,又称链式API,是一种在编程中提供流畅、易读的代码风格的技术。在C#中,它通常通过方法返回自身实例(`return this;`)来实现,允许开发者连续调用多个方法而不会丢失上下文。这种API设计模式在很多流行...
在C#编程中,流畅接口(Fluent Interface)是一种设计模式,它使代码更易于阅读和理解,通过链式方法调用实现。这种接口风格通常用于构建领域特定语言(DSL),使得代码更接近自然语言,提高了代码的可读性和可维护...
这种设计风格尤其适用于领域特定语言(DSL)的构建。在《C#中流畅接口设计的准则-第2部分》中,我们将深入探讨如何有效地应用这一模式,以及它与Windows应用程序开发、Entity Framework和WTL(Windows Template ...
流畅接口(Fluent Interface)是一种编程风格,它鼓励使用方法链(Method Chaining)来编写更易读、更具描述性的代码。方法链允许对象的每个方法返回对象本身,从而使得一系列操作可以通过连续调用来执行。尽管人们...
WinUI提供了丰富的控件集、现代设计风格和 Fluent Design System 支持,使得开发者能够创建出符合最新Windows设计标准的应用。它与传统的Win32 API不同,WinUI更专注于为用户提供一致且美观的界面体验,同时也支持...
4. **XML 格式和MSO接口**:微软提供了Microsoft Office Fluent User Interface Control Identifier (MSO) XML格式,用于描述Ribbon的布局和行为。开发者可能利用这个XML文件来定义选项卡、组和按钮,然后通过VB代码...
- **技术**:例如使用Fluent Interface来创建更自然流畅的API接口。 9. **面向基础设施的准备** - **技术**:例如使用POCO(Plain Old CLR Object)作为一种编码风格。 - **挑战**:处理保存场景时面临的挑战。 ...
在VB中,我们可以通过自定义控件和布局来模仿这种设计风格。 3. ** Aero效果**:Office 2010利用Windows Aero特效,如玻璃效果和半透明,提供了更美观的外观。VB中的Form控件可以设置TransparencyKey和Opacity属性...
2. **Fluent Interface**:Fluent 接口是一种设计模式,使得对象之间的链式调用变得可能,从而提高代码可读性和可维护性。在 wpfluent 中,这可能表现为通过方法链来创建、更新或查询 WordPress 数据。 3. **ORM...
此版本引入了更现代化的设计风格,包括Material Design和Fluent Design的支持,以及对Angular、React和Vue等框架的改进集成。在 `peliculasApp` 中,我们能看到如何使用 `Ionic` 的组件库来创建电影相关的界面,如...
这种编程风格使得代码更易读、更易写,通过链式调用来构建验证规则,使得代码结构清晰且可维护性高。例如,你可以这样创建一个验证规则: ```php $validator = new Respect\Validation\Validator(); $validator->...