英文:
Is it worth defining an interface for a service with a single implementation
问题
在我的Spring应用程序中,通常为每个服务都有一个接口,即使只有一个实现,例如。
public interface FooService {
Foo getFoo(long id)
Iterable<Foo> findAllFoos()
void deleteFoo(long id)
}
@Service
@Transactional
public class FooServiceImpl implements FooService {
// method implementations omitted
}
我认为这种做法起源于过去的时代,当时的模拟库只能为接口生成模拟。但是现代的模拟库,如Mockito,可以像接口一样轻松地模拟类,因此我不确定为具有单一实现的(Spring/Spring Boot)服务定义接口是否有任何实际好处?
英文:
In my Spring application, there's typically an interface for each service, even if there's only a single implementation, e.g.
public interface FooService {
Foo getFoo(long id)
Iterable<Foo> findAllFoos()
void deleteFoo(long id)
}
@Service
@Transactional
public class FooServiceImpl implements FooService {
// method implementations omitted
}
I think this practice originated in the olden days when mocking libraries could only generate a mock for an interface. But modern mocking libraries like Mockito can mock a class just as easily as an interface, so I'm not sure if there's any practical benefit to defining an interface for (Spring/Spring Boot) services with a single implementation?
答案1
得分: 1
我更喜欢在@Service
中使用interface
,因为我们可以将接口设置为公开,而实现则可以设置为包访问级别。这会使作用域更加紧凑。
public interface FooService {
}
@Service
class FooServiceImpl implements FooService {
}
但这仅适用于仅用作门面的服务。
Controller -> 门面服务 -> Spring上下文中的其他类
对于Spring上下文中的“其他类”,可以被“门面服务”使用,我通常不使用接口。
@Service
class FooServiceImpl {
private final FooServiceHelper helper;
@Autowired
public FooServiceImpl(FooServiceHelper helper) {
this.helper = helper;
}
}
我们甚至可以更进一步,可以说:即使有多个实现,也许更好的选择是使用抽象类或默认实现,而不是接口。
英文:
I prefer to use an interface
for @Service
because we can make interface public and implementation package access. So it makes the scope tighter.
public interface FooService {
}
@Service
class FooServiceImpl implements FooService {
}
But it is for service that is used like a facade only.
Controller -> Facade Service -> other classes from Spring context
For "other classes" from Spring context that can be used by Facade Service
I never use interfaces.
@Service
class FooServiceImpl {
private final FooServiceHelper helper;
@Autowired
public FooServiceImpl(FooServiceHelper helper) {
this.helper = helper;
}
}
We can go even further and say: even we have multiple implementations, maybe better to have an abstract class or default implementation rather than an interface.
答案2
得分: -1
在Java应用程序中,创建仅具有单个实现的接口的一个很好的理由是为了实现依赖反转(D,即SOLID中的D)。
例如,在具有洋葱/六边形样式架构的应用程序中,基础设施层包围了应用程序层,应用程序层包围了模型层,您可以在应用程序层定义一个PersonRepository
接口,然后在基础设施层中实现PersonRepository
的JdbcPersonRepository
类。应用程序层中定义的类的方法调用PersonRepository
上的方法来保存和搜索Person
领域对象。基础设施层中的JdbcPersonRepository
允许应用程序在MySQL数据库中使用JDBC保存和搜索Person
对象状态。
在这种设计中,尽管代码执行从应用程序层代码流向基础设施层代码,但代码依赖关系是从基础设施层指向应用程序层的。
搜索洋葱架构、六边形架构、端口和适配器架构以及特别是依赖反转的解释。
英文:
In Java applications, one good reason to create an interface that only has a single implementation is to implement Dependency inversion (D as in SOLID).
For example, in an application that has an onion / hexagonal style architecture with an infrastructure layer surrounding an application layer surrounding a model layer, you might define a PersonRepository
interface in the application layer and a JdbcPersonRepository
class that implements PersonRepository
in the infrastructure layer. Methods of classes defined in the application layer call methods on PersonRepository
to save and search for Person
domain objects. JdbcPersonRepository
in the infrastructure layer allows the application to save and search for Person
object state in a MySQL database using JDBC.
In this design, although code execution flows down from application layer code to infrastructure layer code, code dependencies are directed up from the infrastructure layer to the application layer.
Search for explanations of onion architecture, hexagonal architecture, ports and adapters architecture and, in particular, dependency inversion.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论