【问题标题】:interfaces methods vs classes methods接口方法与类方法
【发布时间】:2018-04-04 03:31:25
【问题描述】:

在 Java-8 中,我们可以有一个方法,例如,屏蔽字符串,有多种方式:

接口实现

public interface StringUtil {
    static String maskString(String strText, int start, int end, char maskChar)
            throws Exception{

        if( Strings.isNullOrEmpty(strText))
            return "";

        if(start < 0)
            start = 0;

        if( end > strText.length() )
            end = strText.length();

        if(start > end)
            throw new Exception("End index cannot be greater than start index");

        int maskLength = end - start;

        if(maskLength == 0)
            return strText;

        StringBuilder sbMaskString = new StringBuilder(maskLength);

        for(int i = 0; i < maskLength; i++){
            sbMaskString.append(maskChar);
        }

        return strText.substring(0, start)
                + sbMaskString.toString()
                + strText.substring(start + maskLength);
    }
}

可以通过以下方式访问:

StringUtil.maskString("52418100", 2, 4, 'x')

现在可以通过类实现如下

public class StringUtil {

    public String maskString(String strText, int start, int end, char maskChar)
                throws Exception{

            if( Strings.isNullOrEmpty(strText))
                return "";

            if(start < 0)
                start = 0;

            if( end > strText.length() )
                end = strText.length();

            if(start > end)
                throw new Exception("End index cannot be greater than start index");

            int maskLength = end - start;

            if(maskLength == 0)
                return strText;

            StringBuilder sbMaskString = new StringBuilder(maskLength);

            for(int i = 0; i < maskLength; i++){
                sbMaskString.append(maskChar);
            }

            return strText.substring(0, start)
                    + sbMaskString.toString()
                    + strText.substring(start + maskLength);
    }
}

这可以通过以下方式访问:

StringUtil su = new StringUtil()
String mask = su.maskString("52418100", 2, 4, 'x')

问题:

在哪种情况下必须首选哪个?到目前为止,我了解到 interface 函数无法通过 mock 测试,所以我必须在我的接口函数之上有一个包装函数 - 简而言之 - 它不是单元测试友好的,而且, 是static,你不能重写接口方法。

如果可以选择编写函数,您还会考虑哪些其他用例?

【问题讨论】:

  • 对我来说,接口就是契约,所以它不能绑定到任何实现。
  • 第一个,甚至你使用第二个,让它静止。
  • 您也可以将static 与第二个一起使用。在这种情况下,对它们进行单元测试会有什么不同?
  • @nullpointer :这只是我添加的utility 方法以供参考....实际用例因代码而异! :)
  • 顺便说一句,抛出通用 java.lang.Exception 是不好的做法。在这种情况下,您可以使用 IndexOutOfBoundsException 或创建自己的 (Runtime-)Exception。

标签: java class interface java-8


【解决方案1】:

对于任何明确开发的实用程序,我建议使用一个类。 java中的Default methods有一个特殊的用途。这些旨在成为需要供应商提供实现的实用方法(还记得吗? - An interface is a contract between Vendor and User)。

例如,如果您正在使用任何第三方库并且有一天供应商引入了新的实用程序功能,那么要么所有客户都必须在界面内覆盖该方法,要么它只是供应商添加静态默认方法。这样,新库的代码仍然向后兼容 (at binary code level)。

确切地说,功能接口的用法和用途在 Oracle 文档中得到了很好的解释,如下所示:-

默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性。

更多内容可以阅读官方文档here

此外,鉴于此目的,在您编写此类方法之前,永远不需要在您最后测试默认方法。如果实用程序方法很复杂,则应对其进行测试。这些实用程序肯定可以进行集成测试。此外,正如您所说,您可以编写一个简单的接口实现并测试这些东西。这类似于测试abstract class。阅读here了解更多详情。

【讨论】:

    【解决方案2】:

    首先,为了在接口中定义方法,您需要使用 default 关键字。通常,接口中没有定义方法——这可能是类和接口之间最大的区别。

    现在,当您希望在不相关的类之间保证共享功能时,您可以使用接口。例如,Serializable 接口保证实现此接口的 ANY 类是Serializable。我不打算在这里解释“Serializable”是什么意思,但想法是,与其让数百个类在杂乱无章的子类树中扩展抽象的 Serializable 类,不如简单地实现 Serializable 并使用 Power of多态性将您的类称为Serializable。在这里查看更多精彩信息:https://www.tutorialspoint.com/java/java_interfaces.htm

    在您的情况下,您需要一个 StringUtil 类,而不是 StringUtil 接口。因为 StringUtil 只包含一个实用程序方法,所以你也想使这个方法 (maskString())static

    【讨论】:

    • defaultstatic 方法可以实现 - 就像问题示例中一样。
    猜你喜欢
    • 2015-01-15
    • 2013-07-21
    • 2011-06-13
    • 2015-12-04
    • 1970-01-01
    • 2018-09-22
    • 2013-01-19
    • 2016-03-15
    相关资源
    最近更新 更多