Hen*_*ues 0 java coupling interface
假设 TaxCalculator 类中有以下方法:
public double calculateTax(double income) {
return income * 0.3;
}
Run Code Online (Sandbox Code Playgroud)
我们在 Main 类中使用这个方法,如下所示:
var calculator = new TaxCalculator();
double tax = calculator.calculateTax(100_000);
System.out.println(tax);
Run Code Online (Sandbox Code Playgroud)
如果我将该方法的实现更改calculateTax为:
public double calculateTax(double income) {
return income * 0.4;
}
Run Code Online (Sandbox Code Playgroud)
我是否需要重新编译 TaxCalculator 类和 Main 类?
我知道这个问题听起来很愚蠢,但我在一次讲座中听说,如果我们不使用接口,我们在紧耦合代码中所做的每一个更改(就像我上面展示的那样)都会迫使我们重新编译所有依赖的类在课堂上我们做出了改变。
这对我来说听起来很奇怪,因为 Main 类不知道我们所做的更改的方法的实现。
预先感谢您的任何帮助!
是的,那位讲师完全错了。更一般地说,这是一个非常过时的概念,曾经是一种常见的说法,并且许多讲师仍然拥护它:
这个想法是,如果你有一个类,你就创建一个串联接口,其中包含该类中的每个(公共)方法;由于类已经占据了概念的名称,因此无法为接口起一个好的名称,因此需要在前面加上 I 前缀。你有 aclass Student和 a 匹配interface IStudent。
不要那样做。这是大量的打字,即使你使用工具自动生成它,每次你改变一个,你就被迫改变另一个,而且没有任何意义。
有一些奇特且大多不相关的方式可以使类的用户Student和Student类代码本身之间获得“更紧密的耦合”,而不是让该用户使用IStudent。听起来您或者更可能是讲师感到困惑,并认为这种紧密耦合意味着任何更改都Student.java需要重新编译。
此外,如果这些例子来自讲座,哦天哪。double对于金融方面来说绝对是不可接受的。这很可能是一个int或long,代表美分(或任何有关货币的“原子货币单位”;便士代表英镑,聪代表比特币,日元代表日元,等等)。在极少数情况下,BigDecimal. 无论如何,不是,永远,double或者float。
您需要重新编译 B,其中 B 使用 A 中的某些内容,如果:
您更改了 A 中由 B 直接使用的常量值,该常量是“CTC”(编译时间常量)。只有原语和字符串可以是 CTC,如果字段是static final,并且立即初始化(相对于在单独的static {}块中初始化),并且其表达式本身是 CTC,则它们是 CTC,这意味着它由文字和之间可能的简单操作组成CTC,例如 中static final int a = 5; static final int b = a + 10;,b也是 CTC。相反,egstatic final long c = System.currentTimeMillis();不是编译时常量,因为System.currentTimeMillis()显而易见的原因不是。
您更改 A 中 B 使用的任何元素的签名。即使调用者(这里是B.java)可以零更改地重新编译。例如,您有A.java:void foo(String param)并更改它void foo(Object param)。即使foo("hello")是对任一方法的有效调用,您仍然需要在此处重新编译。相关元素是方法的名称、参数的类型(不是名称)和返回类型。改变你抛出的异常就可以了。删除 A 中 B 使用的某些内容当然也需要重新编译。
本质上就是这样。接口的插入并不会有意义地更改此列表 - 如果该常量位于接口中,则适用相同的原则(如果更改它,则必须重新编译该常量的用户),并且如果更改签名,则也必须在界面中更改它们,然后我们又回到了开始的地方。
添加接口确实有一些通常不相关的好处。
需要注意的是,任何此类尝试都必须始终回答一个相当尖锐的问题:但是调用者如何创建实例?如果讲师使用,IStudent student = new Student();他们就会把事情搞砸,并且使用界面的一些几乎不相关的好处就消失了。
如果存在有意义的不同实现可用(快速经验法则:如果您能为所有相关类型提供好消息,就是这种情况),那么使用接口是“正确的”,并且这些都不适用。例如,java.util.List是接口,java.util.LinkedList是java.util.ArrayList同一想法的有意义的不同实现。
专门为了测试目的而实现接口会稍微容易一些。然而,模拟和扩展类也是这个问题的通用解决方案,通常也同样有效,更一般地说,制作特定于测试的实现需要更多的小心,而不仅仅是死记硬背地应用“制作镜像接口”原则。
您可以获得额外的访问级别 - 您可以public在类中拥有一些未镜像在界面中的内容,因此无法通过界面“访问”。public当产品并不真正用于外部消费时,有一个很好的理由来制造它们:当您拥有多包装系统时。Java 的模块系统也承认这一点,并且(通过“导出包”概念)还有效地引入了另一个访问级别(public非导出包中的事物无法从其他模块访问,它public不像导出的包)。这已经过时了,即使在多包库中也有办法解决它,而且它实际上并没有太多停止 - 你不能强制调用者“编码到接口” 1
public公开的,但实际上并不用于外部消费,并使用相同的 hackery。| 归档时间: |
|
| 查看次数: |
202 次 |
| 最近记录: |