编写概率算法时的编程结构风格



我有这种随机选择程序执行的程序结构。然而,这种风格不可扩展、不可维护,而且非常容易出错。正如您所看到的,if语句的条件变得越来越长且不可读

你能建议一个更好的编程风格/结构吗?

double aProb = 0.4;
double bProb = 0.2;
double cProb = 0.2;
double dProb = 0.2;
double chance = random.nextDouble();
if ( chance < aProb ) {
    a();
}
if ( chance < bProb + aProb ) {
    b();
}
if ( chance < cProb + bProb + aProb ) {
    c();
}
if ( chance < dProb + cProb + bProb + aProb ) {
    d();
}

我想这很清楚。

如果你想要更短,

double chance = random.nextDouble();
if ((chance -= 0.4) < 0) {
    a();
} else if ((chance -= 0.2) < 0) {
    b();
} else if ((chance -= 0.2) < 0) {
    c();
} else {
    d();
}

(我假设你想要else if)

您可以创建一个新变量来存储aProb + bProb,就像在每个if语句中使用的那样,除了第一个语句,这会使它更短。

您可以创建abstract class IntervalAction类:

public abstract class IntervalAction {
    private final double minBound;
    private final double maxBound;
    public IntervalAction(double minBound, double maxBound) {
        if (minBound < 0) throw new IllegalArgumentException("minBound >= 0");
        if (maxBound > 1) throw new IllegalArgumentException("maxBound <= 0");
        if (minBound > maxBound) throw new IllegalArgumentException("maxBound >= minBound");
        this.minBound = minBound;
        this.maxBound = maxBound;
    }
    public abstract void execute();
    @Override
    public String toString() {
        return "IntervalAction{" +
                "minBound=" + minBound +
                ", maxBound=" + maxBound +
                '}';
    }
}

和注册表类,它将包含所有可用的操作:

public class ActionRegistry {
    public void register(IntervalAction action) {
        if (intersectsWithExistingRange(action))
            throw new IllegalArgumentException("Already have action in that range: " + action);
        // todo registration in internal data structure
    }
    private boolean intersectsWithExistingRange(IntervalAction action) {
        // todo
        return true;
    }
    public void execute(double input) {
        IntervalAction action = find(input);
        if (action == null) throw new IllegalArgumentException("No action found for " + input);
        action.execute();
    }
    private IntervalAction find(double input) {
        // todo
        return null;
    }
}

和一个驱动类:

public class ActionDriver {
    private final ActionRegistry registry;
    private final Random random;

    public ActionDriver() {
        random = new Random(System.currentTimeMillis());
        registry = new ActionRegistry();
        registry.register(new IntervalAction(0, 0.1) {
            @Override
            public void execute() {
                System.out.println(this);
            }
        });
        registry.register(new IntervalAction(0.1, 0.2) {
            @Override
            public void execute() {
                System.out.println(this);
            }
        });
        // so on
    }

    public void act() {
        registry.execute(random.nextDouble());
    }
}
现在,最有趣的部分是如何在ActionRegistry中实现内部数据结构来保存(和搜索)您的操作——所有这些todos在上面的代码示例中。为此,我建议你参考这个SO问题。

最新更新