29

今天我在我的登录表单后面添加了一个额外的安全检查,以减缓暴力攻击。我有多个登录表单,并制作了一个易于调用的函数,可以进行所有检查,然后返回结果。

public static ValidateLoginResult validateLogin(HttpServletRequest request, String email, String password) {

问题是结果不是单个值,结果包括:

boolean ok
String errorMessage
boolean displayCaptcha

为此,我创建了一个新课程。这一切都很好。

但是我经常有方便的实用程序函数返回多个值,并且开始发现每次为结果创建一个新类有点烦人。

有没有更好的方法来返回多个值?还是我只是懒惰?:)

4

7 回答 7

16

不,这种结构在 Java 中不存在,但是您可以查看可能适合您需要的JavaTuples 库并提供一个非常优雅的解决方案。用一个Triplet<Boolean, String, Boolean>

于 2013-05-17T12:42:14.320 回答
5

不确定“最佳实践”,但务实的选择是返回Map<String, String>? 例如

myMap.put("result", "success");
myMap.put("usernameConfirmed", "bigTom");

return myMap;

可能面对一百万个 OO 原则,但我听说您想要避免结果类的扩散。

您也可以Map<String, Object>对存储的对象使用和更严格的类型检查:字符串、布尔值、日期等。

于 2013-05-17T12:43:59.940 回答
5

我真的想不出比将它们封装在一个类中更好、更清晰、更面向对象的方法来从函数返回多个值。

理想情况下,您要返回的多个值在概念上都是同一个类的一部分,因此以这种方式对它们进行分组是有意义的;如果他们不这样做,那么您可能应该将您的函数分解为一些较小的函数,这些函数在函数本身之外返回您需要的每个值。

据我所知,一些 IDE 还具有帮助在一个类中封装多个值的功能:例如,Eclipse 有Refactor --> Extract class...

于 2013-05-17T12:46:03.843 回答
5

您可以定义一个Pair<A, B>类和一个Triplet<A, B, C>类,这将解决返回 2 和 3 值的问题,同时确保类型安全。在这种特殊情况下,签名可以是

public static boolean validateLogin(HttpServletRequest request,
            String email, String password, Pair<Message, Boolean> outputIfOk);

甚至更好的是,在 servlet 上下文中,设置一些有据可查的请求属性可能是有意义的。

如果您发现自己经常需要特殊的类来返回结果,您很可能可以重构这些类以共享一个共同的祖先(例如,有一个包含“ok”和“message”字段的 RequestStatus)。

除此之外,是的,你很懒惰——自定义类总是比 Pairs 和 Triplets 更具自我记录性。

于 2013-05-17T12:49:20.163 回答
1

你可以返回一个 Object[] 数组,java autoboxes,所以它更容易使用。如果只是为了短距离切换,为什么不呢。Ofc 有风险的,可能的类转换问题,nullchecks 等

但它易于编写和使用。

再一次,一个静态内部类被快速创建,如果你把它放在返回它的方法旁边,你也知道在哪里可以找到它(通常在原点附近)

于 2014-06-18T14:14:00.207 回答
0

我可能只是自己走类路线,但根据您希望函数返回的内容,您可能能够通过返回某种值容器而侥幸逃脱。

于 2013-05-17T12:45:06.833 回答
0

这是我从另一个讨论中获得的一个可能的解决方案,并进行了一些改进。它使用带有私有构造函数的公共内部类:

public class Test {
    // Internal storage unit for the two values:
    // 'name' and 'age'.
    private Pair<String, Integer> info;

    public Test() {
        // Empty default constructor.
    }

    /**
     * The two values are stored in the Test class.
     *
     * @param name
     * @param age
     */
    public void setInfo(String name, int age) {
        info = new Pair<>(name, age);
    }

    /**
     * The 'name' and 'age' values are returned in a
     * single object.
     *
     * @return Both values in a Pair object.
     */
    public Pair<String, Integer> getInfo() {
        return info;
    }

    /**
     *  This is an Inner Class for providing pseudo 'tuplet'
     *  as a 'get' return value.
     *
     * @param <F> first internally stored value.
     * @param <S> second internally stored value.
     */
    public class Pair<F, S> {

        public final F first;
        public final S second;

        // This constructor is private to prevent
        // it being instantiated outside its
        // intended environment.
        private Pair(F first, S second) {
            this.first = first;
            this.second = second;
        }

        @Override
        public String toString(){
            return first + ", " + second;
        }
    }

    /**
     * main method for testing of the class only.
     *
     * @param args
     */
    public static void main(String args[]) {
        Test test = new Test();

        test.setInfo("Peter Smith", 35);
        Test.Pair<String, Integer> pair = test.getInfo();

        System.out.println("name: " + pair.first);
        System.out.println("age: " + pair.second);
        System.out.println(pair.toString());
    }
}
于 2019-11-29T03:25:27.070 回答