有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

不变性Java中不使用builder模式的不变性字段

我试图通过创建一个接口及其实现来创建immutable配置,该接口及其实现是package private。只有interface暴露给客户;实现是隐藏的,不能在包外调用Interfaceaccessorsmutators以及一个实例化其实现并返回自身的静态方法。每当调用mutator时,就会创建一个新实例,传递构造函数中的所有字段,以便不更改第一个对象的原始值

以下是我的代码:

package com.example.api;

public interface Config {
    static Config newConfig() {
        return new ConfigImpl();
    }

    String host();
    Config host(String host);
    int port();
    Config port(int port);
    String database();
    Config database(String database);
    String user();
    Config user(String user);
    String password();
    Config password(String password);
}

package com.example.api;

class ConfigImpl implements Config {
    private final String host;
    private final int port;
    private final String database;
    private final String user;
    private final String password;

    public ConfigImpl() {
        this(null, -1, null, null, null);
    }

    public ConfigImpl(String host, int port, String database, String user, String password) {
        this.host = host;
        this.port = port;
        this.database = database;
        this.user = user;
        this.password = password;
    }

    @Override
    public String host() {
        return host;
    }

    @Override
    public Config host(String host) {
        return new ConfigImpl(host, port, database, user, password);
    }

    @Override
    public int port() {
        return port;
    }

    @Override
    public Config port(int port) {
        return new ConfigImpl(host, port, database, user, password);
    }

    @Override
    public String database() {
        return database;
    }

    @Override
    public Config database(String database) {
        return new ConfigImpl(host, port, database, user, password);
    }

    @Override
    public String user() {
        return user;
    }

    @Override
    public Config user(String user) {
        return new ConfigImpl(host, port, database, user, password);
    }

    @Override
    public String password() {
        return password;
    }

    @Override
    public Config password(String password) {
        return new ConfigImpl(host, port, database, user, password);
    }

}

使用API的示例程序:

import com.example.api.Config;

public class App {
    public static void main(String[] args) {
        Config config = Config.newConfig()
            .host("localhost")
            .port(7000)
            .database("mydb")
            .user("admin")
            .password("pwd");

        config.database("mydb2"); // won't change 'mydb'
        Config config2 = config.database("mydb2"); // needs to be assigned to new instance

        System.out.println(config.host() + "|" + config.port() + "|" + config.database() + "|" + config.user() + "|" + config.password());
        System.out.println(config2.host() + "|" + config2.port() + "|" + config2.database() + "|" + config2.user() + "|" + config2.password());
    }
}

这正如期发挥作用:

localhost|7000|mydb|admin|pwd
localhost|7000|mydb2|admin|pwd

我担心的是,这是一个好的设计吗?因为每个mutator/setter都创建了一个news实例,所以它会影响内存和性能吗

如果我目前的设计没有问题,我更喜欢这个

谢谢


共 (1) 个答案

  1. # 1 楼答案

    构建器可能应该有一个单独的build()方法来执行最终的一组操作,例如,对多个字段进行验证,而这些字段不能只用方法签名来解决。感觉更干净:

    Config config = Config.newConfig()
                .host("localhost")
                .build();
    

    关于您的设计,唯一值得关注的是:

    1. 手工编写的样板代码的数量。也许它最终是值得的,但是如果你打算为多个类型实现这一点,你应该考虑一些自动生成代码,例如Lombok ^{}。p>

    2. 由于您没有使用常规的getXXX()setXXX()方法,一些依赖属性方法表示法的框架将无法处理您的类。可能与你的情况完全无关