什么时候需要以接口的形式创建抽象?
您什么时候鼓励针对接口进行编程而不是直接针对具体类进行编程?
我遵循的指导原则是,只要代码需要跨越逻辑/物理边界,尤其是涉及基础设施相关问题时,就创建抽象。
另一个检查点是,由于可能存在额外的问题代码(例如缓存、事务感知、调用 Web 服务而不是进程内执行),依赖项将来是否可能发生变化,或者此类依赖项是否直接引用基础设施集成点。
如果代码依赖于不需要控制来跨越逻辑/物理边界的东西,我或多或少不会创建抽象来与它们交互。
我错过了什么吗?
When do you encourage programming against an interface and not directly to a concrete class?
A guideline that I follow is to create abstractions whenever code requires to cross a logical/physical boundary, most especially when infrastructure-related concerns are involved.
Another checkpoint would be if a dependency will likely change in the future, due to possible additional concerns code (such as caching, transactional awareness, invoking a webservice instead of in-process execution) or if such dependencies have direct references to infrastructure integration points.
If code depends on something that does not require control to cross a logical/physical boundary, I more or less don't create abstractions to interact with those.
Am I missing anything?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
你已经有了正确的想法。我只想添加一些注释...
首先,抽象并不意味着“接口”。例如,“连接字符串”是一个抽象,即使它只是一个字符串......它与所讨论事物的“类型”无关,而是与该事物的使用意图有关。
其次,如果您正在进行任何类型的测试自动化,请寻找编写测试时暴露的痛苦和摩擦。如果您发现自己必须为测试设置太多外部条件,则表明您需要在测试的事物与其交互的事物之间进行更好的抽象。
you have the right idea, already. i would only add a couple of notes to this...
first, abstraction does not mean 'interface'. for example, a "connection string" is an abstraction, even though it's just a string... it's not about the 'type' of the thing in question, it's about the intention of use for that thing.
and secondly, if you are doing test automation of any kind, look for the pain and friction that are exposed by writing the tests. if you find yourself having to set up too many external conditions for a test, it's a sign that you need a better abstraction between the thing your testing and the things it interacts with.
我觉得你说得很好。其中大部分将是一个风格问题。我研究过一些开源项目,其中所有东西都有接口和实现,这有点令人沮丧,但它可能会使迭代开发变得更容易一些,因为任何对象实现都可能会中断,但虚拟对象仍然可以工作。但老实说,我可以通过继承来虚拟任何不过度使用
final
关键字的类。我想在你的列表中添加这样的内容:任何可以被认为是黑匣子的东西都应该被抽象化。这包括您提到的一些内容,但也包括复杂的算法,这些算法可能有多种有用的实现,针对不同的情况具有不同的优势。
此外,对于复合对象,接口经常派上用场。这是像 java 的 swing 库这样的东西完成任何事情的唯一方法,但它对于更普通的对象也很有用。 (我个人喜欢有一个像
ValidityChecker
这样的接口,可以通过“与”或“或”组合方式来组合下级ValidityChecker
。)I think you've said it pretty well. Much of this will be a stylistic thing. There are open source projects I've looked at where everything has an interface and an implementation, and it's kind of frustrating, but it might make iterative development a little easier, since any objects implementation can break but dummies will still work. But honestly, I can dummy any class that doesn't overuse the
final
keyword by inheritance.I would add to your list this: anything which can be thought of as a black box should be abstracted. This includes some of the things you've mentioned, but it also includes hairy algorithms, which are likely to have multiple useful implementations with different advantages for different situation.
Additionally, interfaces come in handy very often with composite objects. That's the only way something like java's swing library gets anything done, but it can also be useful for more mundane objects. (I personally like having an interface like
ValidityChecker
with ways to and-compose or or-compose subordinateValidityChecker
s.)接口传递带来的大部分有用的东西已经说过了。不过我想补充一点:
Most of the useful things that come with the Interface passing have been already said. However I would add:
另外,当
需要以特定方式对多个对象进行操作但又不存在根本相关性时,请使用接口。也许您的许多业务对象访问特定的实用程序对象,并且当它们这样做时,它们需要向该实用程序对象提供自身的引用,以便实用程序对象可以调用特定的方法。在接口中包含该方法并将该接口传递给该实用程序对象。
将接口作为参数传递对于单元测试非常有帮助。即使您只有一种类型的对象具有特定的接口,因此并不真正需要定义的接口,您也可以仅为“fake" 在单元测试中该对象。
与前 2 个项目符号相关,请查看 观察者模式 和 依赖注入。我并不是说要实现这些模式,但它们说明了界面真正有用的地方类型。
另一个变化是实现几个 SOLID 原则,开放封闭原则 和接口隔离原则。就像前面的要点一样,不要因为在任何地方严格实施这些原则而感到压力(至少立即),而是使用这些概念来帮助您将思维从什么对象去哪里转向更多地思考合约和依赖
最后,我们不要把事情搞得太复杂:我们处于 .NET 的强类型世界中。如果您需要调用方法或设置属性,但您传递/使用的对象可能根本不同,请使用接口。
我想补充一点,如果您的代码不会被另一个库引用(至少在一段时间内),那么您可以负责任地决定是否在特定情况下使用接口推迟。如今,“提取接口”重构很容易完成。在我当前的项目中,我有一个正在传递的对象,我想也许我应该切换到一个接口;我并不为此感到压力。
Also, use interfaces when
Multiple objects will need to be acted upon in a particular fashion, but are not fundamentally related. Perhaps many of your business objects access a particular utility object, and when they do they need to give a reference of themselves to that utility object so the utility object can call a particular method. Have that method in an interface and pass that interface to that utility object.
Passing around interfaces as parameters can be very helpful in unit testing. Even if you have just one type of object that sports a particular interface, and hence don't really need a defined interface, you might define/implement an interface solely to "fake" that object in unit tests.
related to the first 2 bullets, check out the Observer pattern and the Dependency Injection. I'm not saying to implement these patterns, but they illustrate types of places where interfaces are really helpful.
Another twist on this is for implementing a couple of the SOLID Principals, Open Closed principal and the Interface Segregation principle. Like the previous bullet, don't get stressed about strictly implementing these principals everywhere (right away at least), but use these concepts to help move your thinking away from just what objects go where to thinking more about contracts and dependency
In the end, let's not make it too complicated: we're in a strongly typed world in .NET. If you need to call a method or set a property but the object you're passing/using could be fundamentally different, use an interface.
I would add that if your code is not going to be referenced by another library (for a while at least), then the decision of whether to use an interface in a particular situation is one that you can responsibly put off. The "extract interface" refactoring is easy to do these days. In my current project, I've got an object being passed around that I'm thinking maybe I should switch to an interface; I'm not stressing about it.
进行单元测试时,接口抽象很方便。它有助于模拟测试对象。它在 TDD 中非常有用,无需实际使用数据库中的数据即可进行开发。
Interfaces abstraction are convenient when doing unit test. It helps for mocking test objects. It very useful in TDD for developing without actually using data from your database.
如果您不需要接口中未找到的类的任何功能...那么为什么不总是更喜欢接口实现呢?
它将使您的代码将来更容易修改,更容易测试(模拟)。
If you don't need any features of the class that aren't found in the Interface...then why not always prefer the Interface implementation?
It will make your code easier to modify in the future and easier to test (mocking).