我主要使用C#、JavaScript和TypeScript。但是最近因为一些原因,需要用到Java,只好重新捡起。回想起来,上一次用Java写出完整的应用,还是1.4版本。这么多年过去了,Java确实进步了很多,比如Stream,var等等,我还是知道一些的。但是用的时候还是有点束缚感,有种用不上的感觉。这肯定和语法习惯有关,但也有Java本身的原因。例如,我经常在C#中使用的“扩展方法”在Java中并不存在。C#的“扩展方法”语法可以在不修改类定义或继承类的情况下,为某些类及其子类添加公共方法。当这些类的对象调用扩展方法时,与调用类本身声明的方法是一样的,没有任何违和之处。为了理解这个语法,这里给出一个例子(不管你会不会C#,只要你有OOP基础,你应该能看懂这个例子)usingSystem;//定义一个Person类而不定义方法publicclassPerson{publicstringName{get;放;}}//下面的类定义了扩展方法PrintName()publicstaticclassPersonExtensions{publicstaticvoidPrintName(thisPersonperson){Console.WriteLine($"Personname:{person.Name}");}}//主程序,提供Main入口,这里使用扩展方法publicclassProgram{publicstaticvoidMain(string[]args){Personperson=newPerson{Name="John"};person.PrintName();}}有OOP基础的开发者常识可以判断:Person类没有定义方法,不应该调用person.PrintName()。但由于PrintName()是静态方法,因此应该可以使用PersonExtensions.PrintName(person)。事实上,如果你尝试像PersonExtensions.PrintName(person)这样的语句,你会发现这句话也能正常工作。但请注意,PrintName()声明的第一个参数已用此修改。这是特定于C#的扩展方法语法。编译器会识别扩展方法,然后将person.PrintName()翻译成PersonExtensions.PrintName(person)来调用——这是一个语法糖。C#在2007年发布的3.0版本中加入了“扩展方法”语法,那是10多年前的事了。不知道Java什么时候支持。但是说Java不支持扩展方法也不完全正确。毕竟有个东西叫Manifold,它以Java编译插件的形式提供扩展方法特性。IDEA中需要插件支持,使用起来感觉和C#差不多。可惜每月$19.9的租金直接把我劝退了。但是程序员往往有一种不撞南墙不回头的执念。没有一个大概的方法来处理这个问题吗?要分析疼痛的来源,就需要使用扩展方法。其实主要原因有一个:想扩展SDK中的类,但是又不想使用静态调用。尤其是需要链式调用的时候,静态方法确实不太好用。还是以Person为例(这次是Java代码):classPerson{privateStringname;publicPerson(Stringname){this.name=name;}publicStringgetName(){returnname;}}classPersonExtension{publicstaticPersontalk(Personperson){...}publicstaticPersonwalk(Personperson){...}publicstaticPersoneat(Personperson){......}publicstaticPersonsleep(Personperson){...}}业务流程是:谈判完出去吃饭,然后回来睡觉。带链接的调用应该是:person.talk().walk().eat().walk().sleep()注:不说换Person,我们假设是第三方SDK封装的,而PersonExtension是我们写的,但是显然不能这样调用。根据PersonExtension中的方法,应该这样调用:sleep(walk(eat(walk(talk(person)))));疼痛?!下面我们来分析一下我们目前除了痛点之外的需求:链式调用没有别的了……链式调用的典型应用场景既然需要链式调用,那么我们来思考一下链式调用的典型应用场景:构建模式。如果我们用构造方式写Extension类,使用的时候把原来的对象封装起来,是不是可以实现链式调用呢?类PersonExtension{privatefinalPersonperson;PersonExtension(Personperson){this.person=person;}publicPersonExtensionwalk(){out.println(person.getName()+":walk");归还这个;(){out.println(person.getName()+":talk");归还这个;}publicPersonExtensioneat(){out.println(person.getName()+":eat");归还这个;PersonExtensionsleep(){out.println(person.getName()+":sleep");归还这个;}}使用起来非常方便:newPersonExtension(person).talk().walk().eat().walk().sleep();引申到一般情况如果就此结束,这篇博文就太水了。解决连锁调用的问题我们走了弯路,但??是人心总是不容易得到满足的。一个新的需求出现了:扩展方法可以编写无数个扩展类。有没有办法让定义在这无数个类中的方法连接调用呢?你看,在当前的包装类中,我们不能调用第二个包装类的方法。但是如果我们可以从当前的包装类切换到第二个包装类不是很好吗?这个转换过程,大致就是获取当前封装的对象(比如person),作为参数传递给下一个封装类的构造函数,构造一个这个类的对象,作为调用体继续写。.这样,我们就需要有个约定:扩展类必须提供一个可以传入封装对象类型参数的构造函数;扩展类必须实现转换为另一个扩展类的方法在程序中,契约通常由接口来描述,所以这里定义一个接口:publicinterfaceExtension
