在循环中获取输入(cli)并进行验证的最佳实践是什么,也像这样恢复?

问题描述 投票:0回答:1

我编写了一个java程序来从用户那里获取一系列输入,一步一步地使用只有在从用户那里获取有效输入后才转到下一个问题的功能,例如,

       while(true){
            while(true){                
                System.out.println("Enter ID (3 digits)");
                int id = sc.nextInt();
                if(validateID(id))
                    break
            }
            while(true){                
                System.out.println("Enter Favourite Number (2 digits)");
                int fav = sc.nextInt();
                if(validateFavNo(fav))
                    break
            }
            System.out.println("ID = "+id+" Favouroite No = "+fav);
        }

这显然不是最好的方法 因此,我想出了一个解决方案,我不确定它是否是最好的方法,如下所示,其中 inputProgress 是一个静态变量,在开始时初始化为 0。

while (true) {

    if (inputProgress == 0) {
        System.out.println("Enter the Product ID");
        pID = sc.nextInt();
        if (vController.validatePIDFormat(pID))
            inputProgress += 1;
        else
            System.out.println("Invalid input");
            continue;
    }

    if (inputProgress == 1) {
        System.out.println("Enter the Product Name");
        pName = sc.next();
        if (vController.validatePNameFormat(pName))
            inputProgress += 1;
        else
            System.out.println("Invalid input");
        continue;
    }

    if (inputProgress == 2) {
        System.out.println("Enter the Product Type");
        String pType = sc.next();
        pTypeID = -1;
        if (pType.contains("commodity")) {
            pTypeID = 1;
        } else if (pType.contains("equity")) {
            pTypeID = 2;
        } else if (pType.contains("derivative")) {
            pTypeID = 3;
        }
        if (pTypeID > 0 && pTypeID < 4) {
            inputProgress += 1;
        } else {
            System.out.println("Invalid input");
            continue;
        }
    }

    if (inputProgress == 3) {
        System.out.println("Enter the Quantity");
        pQuantity = sc.nextInt();
        if (vController.validatePQuantity(pQuantity)) {
            inputProgress += 1;
        } else {
            System.out.println("Invalid input");
            continue;
        }
    }

    Product newProduct = new Product(pID, pName, pQuantity, pTypeID);
    inputProgress = 0;
    return newProduct;
 }

我的问题是,这是否是一个好的方法,或者是否有更好的方法/实践来达到预期的相同结果。

java loops input conceptual
1个回答
0
投票

我不喜欢

while(true)
,总有更好(也更优雅)的解决方案。 在你的情况下,有很多“不优雅”,循环内的所有
return
语句,以及
continue
跳到顶部......不,我不喜欢它。

为了保持你的结构,我们应该让它更“优雅”,就像这样:

public Product readProduct() {
    Scanner sc = new Scanner(System.in);
    MockValidator vController = new MockValidator(); // mock
    // fields outside loop
    int pID = -1;
    String pName = null;
    int pTypeID = -1;
    int pQuantity = -1;

    int inputProgress = 0;
    while (inputProgress < 4) { // Loop exit condition linked to inputProgress. Exit when read all 4 valid inputs
        if (inputProgress == 0) {
            System.out.println("Enter the Product ID");
            pID = sc.nextInt();
            if (vController.validatePIDFormat(pID)) {
                inputProgress += 1;
            } else {
                System.out.println("Invalid input");
            }
        }

        if (inputProgress == 1) {
            System.out.println("Enter the Product Name");
            pName = sc.next();
            if (vController.validatePNameFormat(pName)) {
                inputProgress += 1;
            } else {
                System.out.println("Invalid input");
            }
        }

        if (inputProgress == 2) {
            System.out.println("Enter the Product Type");
            String pType = sc.next();
            pTypeID = -1;
            if (pType.contains("commodity")) {
                pTypeID = 1;
            } else if (pType.contains("equity")) {
                pTypeID = 2;
            } else if (pType.contains("derivative")) {
                pTypeID = 3;
            }
            if (pTypeID > 0) {
                inputProgress += 1;
            } else {
                System.out.println("Invalid input");
            }
        }


        if (inputProgress == 3) {
            System.out.println("Enter the Quantity");
            pQuantity = sc.nextInt();
            if (vController.validatePQuantity(pQuantity)) {
                inputProgress += 1;
            } else {
                System.out.println("Invalid input");
            }
        }
    }

    return new Product(pID, pName, pQuantity, pTypeID);
}

但是,想要更“优雅”,你的代码中有很多重复的概念,所以我们可以提取一些常见的行为。实际上,您想要读取某种类型的每个参数,有时将其转换为另一种类型,验证它并执行此操作,直到结果有效。您可以编写一个通用方法来执行这些操作并将其用于您想要的每个参数!

这就是我要说的

private Product readProductSmart() {
    Scanner sc = new Scanner(System.in);
    MockValidator vController = new MockValidator();

    Map<String, Integer> productTypeMap = Map.of(
        "commodity", 1,
        "equity", 2,
        "derivative", 3
    );

    int pID = readUntilIsValid("Product ID", sc::nextInt, Function.identity(), vController::validatePIDFormat);
    String pName = readUntilIsValid("Product Name", sc::next, Function.identity(), vController::validatePNameFormat);
    int pTypeID = readUntilIsValid("Product Type", sc::next, productTypeMap::get, Objects::nonNull);
    int pQuantity = readUntilIsValid("Quantity", sc::nextInt, Function.identity(), vController::validatePQuantity);

    return new Product(pID, pName, pQuantity, pTypeID);
}

public <S, T> T readUntilIsValid(String name, Supplier<S> supplier, Function<S, T> mapper, Predicate<T> validator) {
    T result;
    boolean valid = false;
    do {
        System.out.println("Enter the " + name);
        result = mapper.apply(supplier.get());
        if (!(valid = validator.test(result))) {
            System.out.println("Invalid input");
        }
    } while (!valid);
    return result;
}

这个解决方案非常“优雅”并且可以扩展以供将来升级

© www.soinside.com 2019 - 2024. All rights reserved.