不变性Java中不使用builder模式的不变性字段
我试图通过创建一个接口及其实现来创建immutable
配置,该接口及其实现是package private
。只有interface
暴露给客户;实现是隐藏的,不能在包外调用Interface
有accessors
和mutators
以及一个实例化其实现并返回自身的静态方法。每当调用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 楼答案
构建器可能应该有一个单独的
build()
方法来执行最终的一组操作,例如,对多个字段进行验证,而这些字段不能只用方法签名来解决。感觉更干净:关于您的设计,唯一值得关注的是:
手工编写的样板代码的数量。也许它最终是值得的,但是如果你打算为多个类型实现这一点,你应该考虑一些自动生成代码,例如Lombok ^{} 。p>
由于您没有使用常规的
getXXX()
和setXXX()
方法,一些依赖属性方法表示法的框架将无法处理您的类。可能与你的情况完全无关