java—根据枚举值执行代码的最佳方法

fwzugrvs  于 2021-08-25  发布在  Java
关注(0)|答案(7)|浏览(594)

下面的代码是我的问题的一个示例。我希望简化代码,而不必在不同的switch语句上重复对相同方法的调用。

public void simulate(String given, Status status) {
    switch (status){
        case A:
            simulateA(given);
            break;
        case B:
            simulateA(given);
            simulateB(given);
            break;
        case C:
            simulateA(given);
            simulateB(given);
            simulateC(given);
            break;
    }

ps 1:调用方法的顺序很重要!
ps 2:我不是在寻找另一种切换的方法,我是在寻找另一种建模问题的方法,可能是在方法中使用某种类组合。

eanckbw9

eanckbw91#

我不知道你的工作性质 enum 但是,如果有许多模拟调用,可以放弃switch语句,这样做。但你目前的做法没有错。如果您的方法是静态的而不是示例,那么这也会有轻微的变化。这样做的一个优点是,它具有扩展的潜力。
有很多其他的方法可以做到这一点。您可以有一个方法引用列表和 enum 参数可以是要按索引调用的方法的变量数组。

public class Simulations {

    static List<BiConsumer<Simulations, String>> sims =
            List.of(Simulations::simulateA, Simulations::simulateB,
                    Simulations::simulateC);

    enum Status {
        A(1), B(2), C(3);
        private int val;
        private Status(int v) {
            this.val = v;
        }
        public int getVal() {
            return val;
        }
    }

    public static void main(String[] args) {
        Simulations simulation = new Simulations();
        simulation.simulate("A", Status.A);
        System.out.println();
        simulation.simulate("B", Status.B);
        System.out.println();
        simulation.simulate("C", Status.C);
    }

    public void simulate(String given, Status status) {
        for (int i = 0; i < status.getVal(); i++) {
            sims.get(i).accept(this, given);
        }
    }

    public void simulateA(String s) {
        System.out.println(s);
    }

    public void simulateB(String s) {
        System.out.println(s);
    }

    public void simulateC(String s) {
        System.out.println(s);
    }

}
rkttyhzu

rkttyhzu2#

在这种情况下,模拟的顺序总是“向下”级联,例如,模拟b是模拟a加上一些额外的。这与遗传模式相匹配,例如,哺乳动物是一种具有某些额外功能的动物。因此,让模拟彼此继承可以修复模式:

interface Simulation
{
    void simulate( final String given );
}

class ASimulation implements Simulation
{
    @Override
    public void simulate( String given )
    {
        // simulate this given!
    }
}

class BSimulation extends ASimulation
{
    @Override
    public void simulate( String given )
    {
        super.simulate( given );
        // simulate this given some more!
    }
}

class CSimulation extends BSimulation
{
    @Override
    public void simulate( String given )
    {
        super.simulate( given );
        // simulate this given even more!
    }
}

请注意,这是脆弱的,因为所有继承树都是脆弱的。另一个解决方案可以通过组合和授权来实现。这称为链:

class LeafSimulation
        implements Simulation
{
    @Override
    public void simulate( String given )
    {
        // simulate this given!
    }
}

class ChainedSimulation
        implements Simulation
{
    private final Simulation delegate;

    ChainedSimulation( final Simulation delegate )
    {
        this.delegate = delegate;
    }

    @Override
    public void simulate( String given )
    {
        delegate.simulate( given );
        // simulate this given some more!
    }
}

要示例化链,请使用以下顺序:

final var aSimulation = new LeafSimulation();
final var bSimulation = new ChainedSimulation( aSimulation );
final var cSimulation = new ChainedSimulation( bSimulation );

这段代码更自然地处理问题陈述,消除了重复,但并不简洁。

bxgwgixi

bxgwgixi3#

设置状态值到方法调用的Map后,可以使用sortedset或enumset.range获取特定值之后的枚举值:

Map<Status, Consumer<String>> simulators = new EnumMap<>(Map.of(
    Status.A, this::simulateA,
    Status.B, this::simulateB,
    Status.C, this::simulateC));

if (!simulators.keySet().equals(EnumSet.allOf(Status.class))) {
    throw new RuntimeException(
        "Not all Status values have simulators defined.");
}

// ...

SortedSet<Status> all = new TreeSet<>(EnumSet.allOf(Status.class));
Collection<Status> remainingValues = all.tailSet(status);

// Or:
//Status[] allStatuses = Status.values();
//Status lastStatus = allStatuses[allStatuses.length - 1];
//Collection<Status> remainingValues = EnumSet.range(status, lastStatus);

for (Status s : remainingValues) {
    simulators.get(s).accept(given);
}
wnvonmuf

wnvonmuf4#

另一个要考虑的选项,它避免了 switch / if . 根据声明操作的Map Status 值,该值可与 getOrDefault 查找未处理值的默认值:

Consumer<String> simA = this::simulateA;
Map<Status, Consumer<String>> actions = new EnumMap<>(Map.of(
        Status.A, simA,
        Status.B, simA.andThen(this::simulateB),
        Status.C, simA.andThen(this::simulateB).andThen(this::simulateC)
));
actions.getOrDefault(status, s -> {}).accept(given);

如果要防止丢失/未处理的Map,则应验证Map(如@vgr answer中所示),或使用异常处理程序替换无操作默认值:

actions.getOrDefault(status,
    s -> { throw new RuntimeException("Missing action for status: "+status); }
).accept(given);
lymgl2op

lymgl2op5#

假设你是第一个 status 这是一个你可以做的事情:

public void simulate(String given, Status status) {
   if (status != Status.A) {
     int indexOfStatus = status.ordinal();
     simulate(given, Status.values()[indexOfStatus - 1]);
   }

   switch (status){
      case A:
        simulateA(given);
        break;
      case B:
        simulateB(given);
        break;
      case C:
        simulateC(given);
        break;
    // here you still need to put all your "simulateX" calls but without repetitions
   }
}
bksxznpy

bksxznpy6#

您不需要为所有案例编写simulatea(给定),只需将其移到顶部即可

public void simulate(String given, Status status) {
   simulateA(given);
   switch (status){
     case C:
       simulateC(given);
     case B:
       simulateB(given);
       break;
     case A:
       break;
 }}
0pizxfdo

0pizxfdo7#

您可以尝试switch语句的fallthrough机制。参考这个
在您的示例中,代码可以(未测试):

编辑:

public void simulate(String given, Status status) {
    switch (status){
        case C:
            simulateC(given);
        case B:
            simulateB(given);
        case A:
            simulateA(given);
    }
}

原件(错误):

public void simulate(String given, Status status) {
    switch (status){
        case A:
            simulateA(given);
        case B:
            simulateB(given);
        case C:
            simulateC(given);
    }
}

当读者头脑中有了错误的概念时,上面的代码比所讨论的代码更清晰、更容易阅读。但情况并非总是如此。我的建议是重新构造代码,以消除重复调用和故障。

相关问题