我理解编码到接口的原理 - 将实现与接口分离,并允许交换接口的实现。
我应该为我写的每个类的接口编码还是过度?我不想将项目中的源文件数量增加一倍,除非它确实值得。
我可以使用哪些因素来决定是否按界面编码?
答案 0 :(得分:32)
一般来说,我同意其他答案:当您知道或预期更改和/或不同的实现时使用接口,或者寻求可测试性。
但提前知道未来会发生什么变化并不总是很容易,特别是如果你不是那么有经验的话。我认为该问题的解决方案是重构:只要不需要,就保持简单(=无接口)。当需要时,只需执行“引入/提取接口”重构(几乎所有体面的IDE都支持)。
当你这样做时,只提取调用者实际需要的那些方法。不要害怕提取多个单独的接口(如果不是所有提取的方法都非常连贯)。
重构的一个驱动程序可能是测试:如果你不能轻易地用类测试某些东西,只考虑引入一个/一些接口。这也允许您使用模拟,这可能会在很多情况下大大简化测试。
编辑:根据Tarski的评论我已经意识到对以前的陈述有一个更重要的情况/调整:
如果你提供一个外部API(对于其他[sub]项目,或者真正将它释放到野外“),那么在API中使用接口(简单值类除外)几乎总是一个好主意。
它允许您在不干扰客户端代码的情况下更改impl。只有在您还需要更改界面时才会遇到问题。不破坏兼容性将是非常棘手的(如果不是不可能的话)。
答案 1 :(得分:11)
当至少满足下列条件之一时,我会使用它:
1)我想将不相关的模块/类彼此分离,我希望它能够被java包依赖项反映出来。
2)解耦在构建依赖性方面很重要
3)当实现可能通过配置更改或在运行时动态更改(通常由于某些设计模式)
4)当我想要一个可测试的类时,我将其“链接点”设置为外部资源接口,以便我可以使用模拟实现。
5)不太常见:当我想要一个选项来限制对某个类的访问时。在这种情况下,我的方法返回一个接口而不是实际的类,因此调用者知道我不希望他对返回的值进行其他操作。
答案 2 :(得分:9)
不,每个班级都不应该有一个界面。这太过分了。
当你需要抽象完成它的工作方式时,你会使用一个界面,并且你确定实现可以改变。
查看java.util Collections API以获得一个好例子。 List接口对于List的一般概念是一个很好的抽象,但你可以看到有很多方法可以实现它:ArrayList,LinkedList等。
更新:那么你设计一个具体类的情况怎么样,在客户端需要一个接口之后决定,然后你通过添加一个接口来破坏你的客户端呢?是的,就是这样。你怎么知道你不知道的?没有任何软件或方法可以解决这个问题。
对您而言,好消息是从具体类中提取界面对于您和您的客户来说都是一种简单的重构。 IDE经常处理这种事情。您和您的客户应该利用它们。
我会说像服务和持久性这样的层应该总是有接口。任何可以代理的东西都应该有一个接口。如果您正在使用Spring AOP,那么您想要用方面装饰的任何东西都应该有一个接口。
模型或值对象(如Person或Address或Phone)不应具有接口。不可变值对象不应该有接口。
其余部分属于灰色区域。用你最好的判断。
答案 3 :(得分:2)
长话短说不。您是该应用程序的创建者,因此您可以很好地了解可以更改的内容。在我看来,有些设计模式书对它有点疯狂,因为它们似乎总是把设计推到界面而不是实现,无论如何。有时,它只是矫枉过正。对于我的最新应用程序(小尺寸),我有一个数据库界面,因为我认为我以后可能会将它移植到网络并切换到MySQL。当然,实际上,从我现有的类开始创建一个数据库接口很容易,稍后只需添加几个小的更改就可以添加“implements myDbInterface”。这是有效的,因为我是唯一的开发人员。在更大的团队或不同类型的产品上,它可能是一个不同的答案。只需使用您的最佳判断(当然,在阅读了所有优秀的SO答案之后)。
答案 4 :(得分:1)
我喜欢考虑在可插拔性和不同行为的可能性很重要时使用接口。服务非常合适。有人可能想要默认实现,但伪造(模拟)等是另一种。这显然意味着应该有一个intf,因为总会有至少2个表格。
另一方面,值类型应该是最终类。永远不应该延长它们。值类型包括Suburb,MimeType等。如果这些使用成分有变化。作为一个目标,我试着在我的价值类型中添加一些行为。验证它包装的简单类型等可能是它最复杂的事情。例如,采用r / g / b的Color类应该验证每个组件在0到255之间并且就是它。
答案 5 :(得分:0)
是您希望更改行为时使用界面。 。将来。
或者你的班级能够以清晰的方式处理变化。
例如
public static void main(String s[])
{
Employee e1=new Employee(new Salesman());
Employee e2=new Employee(new Manager());
system.out.println(e1.performaction());
system.out.println(e1.performaction());
}
Class Employee
{
//which changes frequently
Authority a;
public Employee(Authority a)
{
this.a=a;
}
public String performAction()
{
a.action();
}
}
// --------------------------------------------- ---------------------
interface Authority
{
public String action();
}
class Manager implements Authority
{
public String action()
{
returns "I manages People";
}
class SalesMan implements Authority
{
public String action()
{
returns "I Sell things Company makes ";
}
}