Scala DSL:如何实现多命令链式调用的and关键字语法?
实现
A doX and doY B风格的布尔方法链式判断 当然可以实现这种简洁的语法!核心思路是通过链式调用+中间状态对象来封装原始对象A和要执行的方法序列,避免重复写A doX B && A doY B这种冗余代码。下面分几种常见语言给出具体实现,核心逻辑通用,能支持任意多方法的and串联:
核心设计思路
- 让对象的布尔方法(比如
doX、doY)返回一个中间链式对象,这个对象保存原始对象A和当前已选择的方法。 - 给中间对象添加
and方法,用来接收下一个要执行的方法,更新方法序列并返回自身(保持链式)。 - 最后提供一个入口(比如函数调用、专用方法)接收对象B,依次执行所有方法并返回所有结果的逻辑与(
&&)结果。
这种方案完全不依赖隐式转换,而且对任意数量的方法都通用,扩展性极强。
JavaScript实现(最贴近自然语法)
利用Proxy可以实现几乎和A doX and doY B一致的语法:
class MyObject { constructor(value) { this.value = value; } // 实际业务逻辑方法 _doX(other) { return this.value > other.value; } _doY(other) { return this.value < other.value * 2; } // 封装成链式调用入口 get doX() { return new ChainProxy(this, '_doX'); } get doY() { return new ChainProxy(this, '_doY'); } } class ChainProxy { constructor(sourceObj, methodName) { this.source = sourceObj; this.methods = [methodName]; // 用Proxy实现`and.doY`的语法 return new Proxy(this, { get(target, prop) { if (prop === 'and') { return new Proxy({}, { get(_, method) { target.methods.push(method); return target; } }); } return target[prop]; }, // 重载调用操作符,接收B对象 apply(target, _, args) { const [other] = args; return target.methods.every(method => target.source[method](other)); } }); } } // 使用示例 const A = new MyObject(5); const B = new MyObject(3); // 完美贴近需求语法:A doX and doY B const result = A.doX.and._doY(B); console.log(result); // true
Java实现(静态类型语言方案)
Java是静态类型语言,需要用泛型和函数式接口实现链式调用:
import java.util.ArrayList; import java.util.List; import java.util.function.Function; class MyObject { private int value; public MyObject(int value) { this.value = value; } // 实际业务方法 public boolean doX(MyObject other) { return this.value > other.value; } public boolean doY(MyObject other) { return this.value < other.value * 2; } // 返回链式对象入口 public BooleanChain doX() { return new BooleanChain(this, this::doX); } public BooleanChain doY() { return new BooleanChain(this, this::doY); } } class BooleanChain { private MyObject source; private List<Function<MyObject, Boolean>> methods; public BooleanChain(MyObject source, Function<MyObject, Boolean> firstMethod) { this.source = source; this.methods = new ArrayList<>(); this.methods.add(firstMethod); } // 串联下一个方法 public BooleanChain and(Function<MyObject, Boolean> nextMethod) { this.methods.add(nextMethod); return this; } // 执行所有方法并返回结果 public boolean applyTo(MyObject other) { return this.methods.stream().allMatch(method -> method.apply(other)); } } // 使用示例 public class Main { public static void main(String[] args) { MyObject A = new MyObject(5); MyObject B = new MyObject(3); boolean result = A.doX().and(A::doY).applyTo(B); System.out.println(result); // true } }
C#实现(利用索引器简化语法)
C#可以用索引器来模拟B的传入,让语法更简洁:
using System; using System.Collections.Generic; using System.Linq; public class MyObject { public int Value { get; set; } // 实际业务方法 public bool DoX(MyObject other) => this.Value > other.Value; public bool DoY(MyObject other) => this.Value < other.Value * 2; // 返回链式对象入口 public BooleanChain<MyObject> DoX() => new BooleanChain<MyObject>(this, this.DoX); public BooleanChain<MyObject> DoY() => new BooleanChain<MyObject>(this, this.DoY); } public class BooleanChain<T> { private readonly T _source; private readonly List<Func<T, bool>> _methods; public BooleanChain(T source, Func<T, bool> firstMethod) { _source = source; _methods = new List<Func<T, bool>> { firstMethod }; } // 串联下一个方法 public BooleanChain<T> And(Func<T, bool> nextMethod) { _methods.Add(nextMethod); return this; } // 用索引器接收B对象,执行所有方法 public bool this[T other] => _methods.All(method => method(other)); } // 使用示例 class Program { static void Main() { var A = new MyObject { Value = 5 }; var B = new MyObject { Value = 3 }; bool result = A.DoX().And(A.DoY)[B]; Console.WriteLine(result); // True } }
扩展说明
- 这些方案都支持无限串联方法,比如
A doX and doY and doZ B只需要在链式调用中继续添加.and(doZ)即可。 - 完全不需要修改原有业务方法的逻辑,只需要封装一层链式入口即可,对原有代码侵入性极低。
- 如果需要实现
or逻辑,只需要把allMatch(或every)改成anyMatch(或some)即可,非常灵活。
内容的提问来源于stack exchange,提问作者THIS USER NEEDS HELP
相关产品推荐
相关产品推荐

