如何在春季使用自动装配的bean创建简单工厂模式? [英] How to create a Simple Factory Pattern with autowired beans in Spring?
问题描述
我有一个具有4种非常相似方法的控制器,该控制器在远程服务器上调用API以对不同类型的用户执行不同的操作.这些API调用之间的变化只是端点和一些参数.
I had a controller with 4 very similar methods, calling an API on a remote server to perform different actions on different types of users. What changed between these API calls are just the endpoint and some parameters.
因此,这4种方法都用非常相似的代码调用了服务:它们从服务器获取了令牌,设置了参数,返回了API的响应.由于稍后将添加更多操作,因此我决定使用使用Factory Method模式创建ServiceFactory并在服务上使用Template模式以避免代码重复.
Therefore, these 4 methods all called services with very similar code: they got a token from the server, set the parameters, return the API's response. Since more actions will be added later, I decided to use create a ServiceFactory using the Factory Method pattern and use the Template pattern on the services to avoid code duplication.
我的问题是,为了使工厂能够自动装配服务,需要将其耦合到它们,我必须在每个实现中都@Autowire
.有更好的解决方案吗?
My problem is that in order for the factory to autowire the services, it needs to be coupled to them, I have to @Autowire
every implementation. Is there a better solution?
这是我到目前为止的代码:
Here's the code I have so far:
@RestController
public class ActionController {
@Autowired
private SsoService ssoService;
// this is the factory
@Autowired
private ServiceFactory factory;
@PostMapping("/action")
public MyResponse performAction(@RequestBody MyRequest request, HttpServletRequest req) {
// template code (error treatment not included)
request.setOperator(ssoService.getOperator(req));
request.setDate(LocalDateTime.now());
return serviceFactory.getService(request).do();
}
}
服务工厂
@Component
public class ServiceFactory {
@Autowired private ActivateUserService activateUserService;
@Autowired private Action2UserType2Service anotherService;
//etc
public MyService getService(request) {
if (Action.ACTIVATE.equals(request.getAction()) && UserType.USER.equals(request.getUserType()) {
return activateUserService;
}
// etc
return anotherService;
}
}
服务库,实现MyService接口
public abstract class ServiceBase implements MyService {
@Autowired private ApiService apiService;
@Autowired private ActionRepository actionRepository;
@Value("${api.path}") private String path;
@Override
public MyResponse do(MyRequest request) {
String url = path + getEndpoint();
String token = apiService.getToken();
Map<String, String> params = getParams(request);
// adds the common params to the hashmap
HttpResult result = apiService.post(url, params);
if (result.getStatusCode() == 200) {
// saves the performed action
actionRepository.save(getAction());
}
// extracts the response from the HttpResult
return response;
}
}
服务实施(共有4个)
@Service
public class ActivateUserService extends ServiceBase {
@Value("${api.user.activate}")
private String endpoint;
@Override
public String getEndpoint() {
return endpoint;
}
@Override
public Map<String,String> getParams(MyRequest request) {
Map<String, String> params = new HashMap<>();
// adds custom params
return params;
}
@Override
public Action getAction() {
return new Action().type(ActionType.ACTIVATED).userType(UserType.USER);
}
}
推荐答案
您可以@Autowired
MyService
的List
,这将创建所有实现MyService
接口的bean的List
.然后,您可以向MyService
添加一个接受MyRequest
对象的方法,并确定该方法是否可以处理该请求.然后,您可以过滤MyService
的List
以找到可以处理请求的第一个MyService
对象.
You can @Autowired
a List
of MyService
, which will create a List
of all beans that implement the MyService
interface. Then you can add a method to MyService
that accepts a MyRequest
object and decides if it can handle that request. You can then filter the List
of MyService
to find the first MyService
object that can handle the request.
例如:
public interface MyService {
public boolean canHandle(MyRequest request);
// ...existing methods...
}
@Service
public class ActivateUserService extends ServiceBase {
@Override
public boolean canHandle(MyRequest request) {
return Action.ACTIVATE.equals(request.getAction()) && UserType.USER.equals(request.getUserType());
}
// ...existing methods...
}
@Component
public class ServiceFactory {
@Autowired
private List<MyService> myServices;
public Optional<MyService> getService(MyRequest request) {
return myServices.stream()
.filter(service -> service.canHandle(request))
.findFirst();
}
}
请注意,上述ServiceFactory
实现使用Java 8+.如果无法使用Java 8或更高版本,则可以通过以下方式实现ServiceFactory
类:
Note that the ServiceFactory
implementation above uses Java 8+. If it is not possible to Java 8 or higher, you can implement the ServiceFactory
class in the following manner:
@Component
public class ServiceFactory {
@Autowired
private List<MyService> myServices;
public Optional<MyService> getService(MyRequest request) {
for (MyService service: myServices) {
if (service.canHandle(request)) {
return Optional.of(service);
}
}
return Optional.empty();
}
有关将@Autowired
与List
结合使用的更多信息,请参见 Autowire按类型将bean引用到列表中..
For more information on using @Autowired
with List
, see Autowire reference beans into list by type.
此解决方案的核心是将判断MyService
实现是否可以处理MyRequest
的逻辑从ServiceFactory
(外部客户端)转移到MyService
实现本身.
The core of this solution is moving the logic of deciding if a MyService
implementation can handle a MyRequest
from the ServiceFactory
(an external client) to the MyService
implementation itself.
这篇关于如何在春季使用自动装配的bean创建简单工厂模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!