gpt4 book ai didi

java - 使用 Enum 作为功能齐全的对象(像本例一样使用动态调度)是否意味着滥用它或不是一个好的设计?

转载 作者:行者123 更新时间:2023-12-02 07:56:21 25 4
gpt4 key购买 nike

我已经实现了一个角色枚举,其中包含带有等级的角色定义。对于 getAssignableRoles() 部分,我的同事说这是滥用 Enum 或过度工程,并指出用这种形式无法读取它。

public enum Role {
USER("ROLE_user", 1),
CUSTOMER("ROLE_customer", 2),
PRODUCT_OWNER("ROLE_product_manager", 3) {
@Override
public List<Role> getAssignableRoles() {
return getLowerRankedRoles().stream().filter(e -> !e.equals(CUSTOMER_ADMIN)).collect(Collectors.toList());
}
},
CUSTOMER_ADMIN("ROLE_customer_admin", 3) {
@Override
public List<Role> getAssignableRoles() {
return getLowerRankedRoles().stream().filter(e -> !e.equals(PRODUCT_OWNER)).collect(Collectors.toList());
}
},
USER_MANAGER("ROLE_user_manager", 5),
ADMIN("ROLE_admin", 99);

private final String value;
private final int rank;

public String getValue() {
return value;
}
public int getRank() {
return rank;
}

Role(String value, int rank) {
this.value = value;
this.rank = rank;
}

public static Role findByAbbr(String abbr) {
return Arrays.stream(values()).filter(value -> value.value.equals(abbr)).findFirst().orElse(UNKNOWN);
}

public String getExactValue() {
return value.replaceFirst("^ROLE_", "");
}

// Each role has a distinct grant rank but for some roles even if they have same grant level their role assigning changes in the context.
public List<Role> getAssignableRoles() {
return getLowerRankedRoles();
}

protected List<Role> getLowerRankedRoles() {
return Arrays.stream(values()).filter(value -> value.rank <= rank).collect(Collectors.toList());
}

public static Predicate<String> isInRealm() {
return (String role) -> (Arrays.stream(values()).anyMatch(value -> value.value.equals(role)));
}

}

我想做的是,在客户端代码中能够像这样调用它

Role.findByAbbr(role).getAssignableRoles()

像这样使用枚举是一个好的实践或设计吗?我们可以从 Enum 中获得大部分动态调度功能吗?

最佳答案

这个问题实际上比乍一看更有趣。我在这里看到两个不同的点:

  1. 您的角色没有可变状态;
  2. 您需要访问所有不同角色的列表,该列表是固定的。

谈到第 (1) 点,如果一个值不可变,则称为常量,而 Java enum 正是这样:常量值集 ( see the official Java tutorial )。

第 (2) 点指的是 Java enumvalues() 预定义方法的功能。事实上,使用其他策略实现 Role.findByAbbr(abbr) 会很困惑。

让我进一步详细说明这一点。如果您不希望客户端代码能够创建新角色,常见的策略是利用包友好的可见性范围。在包 com.example.role 中声明一个抽象类 Role

package com.example.role;

public abstract class Role {
private int rank;
private String value;

Role(String value, int rank) {
this.value = value;
this.rank = rank;
}

// Other methods...
}

请注意,构造函数上没有显式可见性修饰符(因此它是包友好的)。只有同一包内的类才能调用类Role的构造函数,因此只能在同一包内继承***。

package com.example.role;

public class UserRole extends Role {
private static final UserRole instance = new UserRole();

private UserRole() {
super("ROLE_user", 1);
}

public UserRole getInstance() {
return instance;
}
}

我们正在尝试使用普通 Java 类来模拟您的 enum,因此我们还使用单例模式来为每个角色提供一个实例。

一切都很简单,但是当涉及到 values() 预定义方法时,情况就发生了变化。

package com.example.role;

public final class Roles {
private static Collection<Role> values = Collections.unmodifiableList(Arrays.asList(
UserRole.getInstance(),
CustomerRole.getInstance(),
ProductOwnerRole.getInstance(),
CustomerAdminRole.getInstance(),
UserManagerRole.getInstance(),
AdminRole.getInstance()));

private Roles() {
}

public static Collection<Role> values() {
return values;
}

// Other methods...
}

每次添加新的角色时,您都必须记住将其添加到列表中。太丑了。

客户端代码的界面仍然很漂亮,如下所示:

Collection<Role> assignables = Roles.getAssignableRolesFor(role);

总之,您对 enum 属性的利用看起来并没有那么糟糕。您的角色是常量,预定义的 values() 方法为您提供了开箱即用的强大功能。将所有排名和名称放在一个地方而不是分散在多个文件中也非常好。

<小时/>

*** 用户可能会在其客户端代码中创建一个同名的包并创建一个新的角色,但这是一个不好的做法,我什至不会考虑。

关于java - 使用 Enum 作为功能齐全的对象(像本例一样使用动态调度)是否意味着滥用它或不是一个好的设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59586654/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com