微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在没有静态方法的情况下设计 Java 流畅的 DSL API

如何解决如何在没有静态方法的情况下设计 Java 流畅的 DSL API

定义 Java fluent API 的方法有多种:

  • 使用静态类/方法 + 内部 ThreadLocal获取 DSL 实例
  • 使用基于 setter/getter 的方法链接 API。我个人不喜欢它的可读性,例如查看一些 Spring Security 代码示例。

有没有办法创建一个更具可读性的 Java DSL,比如 Kotlin 中的流畅方法?例如,具有 Computer/cpu属性gpu 类和驱动器等嵌套 DSL 类(注意:我想进一步嵌套 ssd 和 hdd,例如定义partitions

public class Main {

    public static void main(String[] arguments) {
        Computer computer = Computer.build("Gaming PC").cpu("AMD 5950X").gpu("Lol rly?");
        computer.drives(() {
            ssd("1TB","m2");
            hdd("10TB","SATA");
        });
        computer.print();
    }

    public static class Computer {

        private final Map<String,String> attributes;

        private Computer() {
            this.attributes = new LinkedHashMap<>();
        }

        public static Computer build(String name) {
            Computer computer = new Computer();
            computer.attributes.put("name",name);
            return computer;
        }

        public Computer cpu(String modelName) {
            attributes.put("cpu",modelName);
            return this;
        }

        public Computer gpu(String modelName) {
            attributes.put("gpu",modelName);
            return this;
        }

        // Todo: Add ssd and hdd. How?

        public void print() {
            for (Map.Entry<String,String> entry : attributes.entrySet()) {
                System.out.println(entry.getKey() + " = " + entry.getValue());
            }
        }
    }
}

上面的例子无法编译。但是有没有办法用常规类/抽象类甚至接口 [使用方法?] 来实现它。像这样:

public class Main {

    public static void main(String[] arguments) {
        Computer computer = Computer.build("Gaming PC").cpu("AMD 5950X").gpu("Lol rly?");
        computer.drives((new DriveManager() {
            ssd("1TB","SATA");
        });
        computer.print();
    }

    public static class DriveManager {

        private Computer computer;

        public void setComputer(Computer computer) {
            this.computer = computer;
        }

        public void ssd(String size,String interfaceType) {
            computer.ssd(size,interfaceType);
        }

        public void hdd(String size,interfaceType);
        }
    }
}

但是如何调用 setComputer

解决方法

可以使用反射和匿名实例。

您只需要它用于驱动器

Computer computer = new Computer("Gaming PC") {
    MainboardComponent cpu = new CPU("AMD 5950X");
    MainboardComponent gpu = new GPU("Lol rly?");

    Drive ssd = new SSD("1TB","m2");
    Drive hdd = new HDD("10TB","SATA") {
        Partition hdd1 = ...;
        Partition hdd2 = ...;
    };
}

但是这会隐藏这些字段。

然而,这对于您可以在多个级别(受保护的字段、预定义的规则、I/O 端口)上使用继承的语法之类的东西很有用。优点是容器基类可以提供组件类和受保护的成员。

通过让 ComputerBuilder 有一个嵌套的 DriveBuilder,一个纯流畅的界面也是可能的。

Computer computer = Computer.build("Gaming PC")
    .cpu("AMD 5950X")
    .gpu("Lol rly?")
    .drives()
        .ssd("1TB","m2")
        .hdd("10TB","SATA")
        .endDrives()
    .end();

第三种选择是使用可变参数方法 ComputerBuilder drives(DriveBuilder... dds);(Drive 或 DriveBuilder)。

Computer computer = Computer.build("Gaming PC")
    .cpu("AMD 5950X")
    .gpu("Lol rly?")
    .drives(Drive.ssd("1TB","m2"),Drive.hdd("10TB","SATA"));

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?