Java中不使用生成器模式的不可变字段
我试图通过创建一个接口及其实现来创建Java中不使用生成器模式的不可变字段,java,immutability,Java,Immutability,我试图通过创建一个接口及其实现来创建不可变的配置,该接口及其实现是包私有的。只有接口向客户端公开;实现是隐藏的,不能在包外部调用接口具有访问器和变异器以及一个实例化其实现并返回自身的静态方法。每当调用mutator时,就会创建一个新实例,传递构造函数中的所有字段,以避免更改第一个对象的原始值 这是我的密码: package com.example.api; public interface Config { static Config newConfig() { ret
不可变的
配置,该接口及其实现是包私有的
。只有接口
向客户端公开;实现是隐藏的,不能在包外部调用<代码>接口具有访问器
和变异器
以及一个实例化其实现并返回自身的静态方法。每当调用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实例,所以它会影响内存和性能吗
如果我当前的设计没有问题,我更喜欢这个而不是构建器模式
谢谢。生成器可能应该有一个单独的
build()
方法来执行最终的一组操作,例如,对多个字段进行验证,而这些字段不能仅用方法签名来处理。感觉更干净:
Config config = Config.newConfig()
.host("localhost")
.build();
关于您的设计,唯一值得关注的是:
getXXX()
和setXXX()
方法,一些依赖属性方法表示法的框架将无法处理您的类。可能与你的情况完全无关构建器可能应该有一个单独的
build()
方法来执行最后一组操作,例如,对多个字段进行验证,而这些字段不能仅用方法签名来解决。感觉更干净:
Config config = Config.newConfig()
.host("localhost")
.build();
关于您的设计,唯一值得关注的是:
getXXX()
和setXXX()
方法,一些依赖属性方法表示法的框架将无法处理您的类。可能与你的情况完全无关如果将其用于数据库配置,则性能实际上是无关紧要的:与打开数据库相比,创建这几个对象的成本很小。根据个人喜好,我会调用使用*返回新实例
,或其他方法,为了更清楚地说明返回了一个新实例。为什么在调用访问器时要创建一个新实例?当调用突变子时,这样做不是更合适吗?@Andreas My bad。它应该是mutator
。我已经对它进行了更新。@AndyTurner最初我是对
使用,但后来删除了它。IDK但是当我看到Spark框架的request
和response
方法时,它们看起来更简洁,更接近访问器,参数就是区别。无论如何,这只是偏好的问题。如果您将其用于数据库配置,那么性能实际上是无关紧要的:与打开数据库相比,创建这几个对象的成本很小。根据个人偏好,我会调用使用*
返回新实例的方法,或者其他方法,为了更清楚地说明返回了一个新实例。为什么在调用访问器时要创建一个新实例?当调用突变子时,这样做不是更合适吗?@Andreas My bad。它应该是mutator
。我已经对它进行了更新。@AndyTurner最初我是对
使用,但后来删除了它。IDK但是当我看到Spark框架的request
和response
方法时,它们看起来更简洁,更接近访问器,参数就是区别。不管怎样,这只是偏好的问题。谢谢你的回复。我从来都不是像Lombok
这样的自动生成库的粉丝。我更喜欢在Lombok
特别适合的地方编写样板。我宁愿等待记录
,它们将进入Java14
。是的。我知道如果不使用常规的getter
和setter
方法,可能会导致其他框架无法工作,如果它们依赖于它的话。现在,是的,它们与我的情况完全无关。就验证而言,我将考虑builder模式中的build
。感谢您的回复。我从来都不是像Lombok
这样的自动生成库的粉丝。我更喜欢在Lombok
特别适合的地方编写样板。我宁愿等待记录
,它们将进入Java14
。是的。我知道如果不使用常规的getter
和setter
方法,可能会导致其他框架无法工作,如果它们依赖于它的话。现在,是的,它们与我的情况完全无关。就验证而言,我将考虑builder模式中的build
。