假设我们正在制作一个解析器。一种实现可能是:
public sealed class Parser1
{
public string Parse(string text)
{
...
}
}
或者我们可以将文本传递给构造函数:
public sealed class Parser2
{
public Parser2(string text)
{
this.text = text;
}
public string Parse()
{
...
}
}
在这两种情况下,使用都很简单,但与其他情况相比,是什么意思使参数输入到Parser1
?当他们查看API时,我发送给同事程序员的消息是什么?此外,在某些情况下是否存在任何技术优势/劣势?
当我意识到在第二个实现中接口将毫无意义时,会出现另一个问题:
public interface IParser
{
string Parse();
}
...第一个界面上的界面至少可以用于某种目的。这是否意味着什么,一个类是“可接口的”?
答案 0 :(得分:2)
在两种情况下使用都很简单,但是对于Parser1启用参数输入与其他参数相比意味着什么呢?
如果在构造函数中指定参数,则暗示该参数将在整个类中使用。如果在setter方法中指定参数,则表示在创建类的实例时可能不知道参数的值。
这是一个需要setter方法的真实示例。
public class A {
private B b;
}
public class B {
private A a;
}
假设类A和B具有所有适当的getter和setter。构造函数是两个类的空构造函数。
为了初始化这两个类,你必须编写看起来像这样的代码。
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
这是否特别表示某个类是否可“接口”?
通常,当有多个具体类满足接口要求时,可以编写接口。
例如,在Java中,List
接口由ArrayList
和LinkedList
实现。
编写接口的另一个原因是,您希望建立具体类必须实现的必需方法,即使只编写一个具体类。
有时,抽象类是定义基类的更好方法。这取决于你想要完成的任务。
答案 1 :(得分:0)
一般来说,即使您只有一个实现,界面也是一个好主意。它使您的代码更加灵活,特别是因为您可以采用依赖注入原则:在类的构造函数中注入具体实例。它使您的代码也非常可测试,并且您的类的用户知道会发生什么,并且还知道它们的依赖性。这样做可以将解析器注入其他类,例如:
public class Worker
{
private IParser _parser;
public Worker(IParser parser)
{
_parser=parser;
}
}
针对接口进行编程还会将代码与实际实现分离。例如:域层中的类使用存储库接口;但对具体的存储库实现一无所知,因为它们是在运行时注入的。因此,该域名与基础设施问题无关。
关于text
参数:在您的情况下,Parse
操作的参数可能更好,因为它不会在该操作之外使用,您可以调用Parse
方法多次使用不同的字符串。如果你在构造函数中执行此操作,则意味着您可能有多个操作可以使用它,因此它更像是操作的全局变量。