我正在使用Spring Boot 3开始一个新项目。我们仍处于项目的早期阶段,仍在定义一些东西。所以,我这么说。我的问题是:
我要解决的问题:处理所有业务逻辑的服务层在实体之间共享公共功能,例如:CRUD功能和其他功能。
建议:创建具有所有通用功能的通用接口。然后:创建一个抽象类来实现这个接口并重写;为什么是抽象的,因为我想防止向父接口添加新函数并检查所有实现的用例。
下面是我实现的一个例子:
// Project stucture.
main-project
|-src
|--main
|-java
|-com.project
|-entities
|-repositories
|-service
| |-implementation
|-rest
现在我们都知道实体、存储库和rest包里面是什么,下面是我的服务包实现:
BaseCommonOperationInterface
public interface BaseCommonOperationInterface<E, V> {
E createItemOf(V requestDto);
E updateItemfrom(final Long identifier, V requestDto);
void deleteItem(final Long identifier);
Optional<E> findSingleRecordByIdentifier(Long skillDicCategoryId);
List<E> listAllItems();
//more common function...
}
BusinessBaseAbstract
puiblic abstract class BusinessBaseAbstract<E, V> implements BaseCommonOperationInterface<E, V>{
//Here override all methods from interface...
@Override
public List<E> listAllItems() {
return Collections.emptyList();
}
//...
}
DictionaryService
public interface DictionaryService implement BaseCommonOperationInterface<DictionaryEntity, DictionaryrequestDto>{}
DictionaryServiveImpl
@RequieredArgConstructor
@Service
public class DictionaryServiveImpl extends BusinessBaseAbstract<DictionaryEntity, DictionaryrequestDto> implements DictionaryService{
private final DictionaryRepository dictionaryRepository;
//I can override eather single common function or all of them
@override
public List<DictionaryEntity> listAllItems(){
return dictionaryRepository.findAll()
}
// all the methods I need overrided here...
}
DictionaryController
@RestController
public class DictionaryController{
private final DictionaryService service;
@GetMapping("/dictionary")
public List<DictionarEntity> getAllofThem(){
return service.listAllItems();
}
//Here rest of implementations...
}
为什么不从控制器调用DictionaryRepository呢?因为我们希望尽可能保持Rest控制器的干净,并将所有业务逻辑委托给Service包。
这个模式有意义吗?有优势和劣势吗?还有其他的模式可以应用于抽象的公共函数吗?
这不是个好主意。
当你想使用实现接口的类的实例而不知道它们的具体类时,拥有一些实现接口的类是一个好主意。
如果您有一个所有XxxServiceImpl
类的集合,并且想要在每个BaseCommonOperationInterface
上运行一个方法,那么接口将是有用的。但服务通常不是这样使用的——它们被显式地注入到需要它们的控制器类中。
拥有一个公共接口意味着当你向一个服务添加一个方法时,你需要将它添加到所有服务中——但可能这些服务是不同的。
你提出了一个抽象基类,这样你就可以为一些服务提供一个无操作的实现,但这只会让你的服务变得混乱——我们应该期望调用这个方法来做一些事情吗?服务的用户会想知道为什么一个特定的服务上有一个它不需要的方法,不知道接口需要它,而实现什么也不做。
最后,如果你有一个很好的理由强制一个方法存在于你的所有服务上,那么是的,使用接口,但是不要在抽象类中放置一个空的实现。
如果没有抽象类,你将不得不考虑:这个服务需要什么样的实现来实现这个新方法?如果存在默认实现,那么在添加新方法时很容易忽略考虑服务。