我理解编码到接口的原则 - 从接口中分离实现,允许接口的实现互换。
我是否应该为我编写的每个类编写接口,还是这太过头了?我不想在项目中将源文件数量翻倍,除非真的值得。
有哪些因素可以用来决定是否使用接口编码?
总的来说,我同意其他答案:在你知道或预料到变化和/或不同实现时使用接口,或者考虑可测试性。
但是,如果你不是很有经验,很难提前知道未来可能发生什么变化。我认为解决这个问题的方法是重构:只要不需要,就保持简单(= 不用接口)。当需要时,只需进行“引入/提取接口”重构(几乎所有良好的IDE都支持此功能)。
在提取接口时,只提取调用者实际需要的方法。如果提取出的方法并非真正相关,请毫不犹豫地提取出更多单独的接口。
重构的一个驱动因素可能是测试:如果只使用类无法轻松测试某些内容,则考虑引入一个或多个接口。这也将允许您使用Mocking,在许多情况下大大简化测试。
编辑:根据Tarski的评论,我意识到之前声明的一个更重要的情况/调整:
如果您提供外部API(用于其他[子]项目或真正发布到“野外”),则在API中使用接口(除了简单的值类)几乎总是一个好主意。
它将使您可以在不干扰客户端代码的情况下更改实现。只有在您还必须更改接口时才会出现问题。不破坏兼容性将非常棘手(如果不是不可能的话)。
我在以下情况下使用它:
1) 当我想将不相关的模块/类解耦,并希望Java包依赖反映这一点。
2) 在构建依赖方面解耦很重要时
3) 当实现可能通过配置或运行时动态更改(通常是由于某些设计模式)
4) 当我想让一个类易于测试时,我将其“链接点”与外部资源接口连接,以便可以使用模拟实现。
5) 不太常见:当我想有一个选项来限制对某个类的访问时。在这种情况下,我的方法返回一个接口而不是实际的类,这样调用者就知道我不希望他对返回值执行其他操作。
我认为当可插拔性和潜在的不同行为很重要时,应该使用接口。服务是完美的选择。一个人可能想要一个默认实现,但模拟等另外一种方式也可以。这显然意味着应该有一个接口,因为至少会有两种形式。
另一方面,值类型应该是final类。它们不应该被扩展。值类型包括像Suburb、MimeType之类的东西。如果有这些的变化,请使用组合。作为目标,我尽量在我的值类型中放入尽可能少的行为,如果有的话。验证它所包装的简单类型可能是它最复杂的事情。例如,一个颜色类,它需要r/g/b,应该验证每个分量是否在0到255之间,仅此而已。
当你期望某个行为在未来发生变化时,可以使用接口。或者使用能够清晰处理变化的类。
例如:
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 ";
}
}