英文:
Looking up and selecting the correct interface implementation based on enum value in Spring Boot
问题
Spring Boot这里。我有一个接口:
```java
public interface AnalyticsService {
    AnalyticsResult analyze(AnalyticsRequest request);
}
我有几十个针对这个接口的不同实现,每个实现都需要被标记为 @Service:
@Service
public class FizzAnalyticsService implements AnalyticsService {
    @Override
    public AnalyticsResult analyze(AnalyticsRequest request) {
        // ...
    }
}
@Service
public class BuzzAnalyticsService implements AnalyticsService {
    @Override
    public AnalyticsResult analyze(AnalyticsRequest request) {
        // ...
    }
}
// ... 等等(几十个)
我想创建一个枚举,比如说 AnalyticsType:
public enum AnalyticsType {
    FIZZ,
    BUZZ,
    ...(几十个)
}
然后以某种方式将每个枚举值映射/绑定到不同的 AnalyticsService 实现,以便“客户类”可以在运行时选择正确的实现,类似于:
@Service
public class SomeService {
    @Autowired
    private FizzAnalyticsService fizzAnalyticsService;
    @Autowired
    private BuzzAnalyticsService buzzAnalyticsService;
    // ... 等等
    public void doSomething(AnalyticsType type, AnalyticsRequest request) {
        AnalyticsService analyticsService = ???(按 'type' 查找)
        AnalyticsResult result = analyticsService.analyze(request);
    }
}
在Spring Boot中,如何处理这种类型的查找是什么合适的解决方案?
<details>
<summary>英文:</summary>
Spring Boot here. I have an interface:
public interface AnalyticsService {
AnalyticsResult analyze(AnalyticsRequest request);
}
I have dozens of different impls for this interface, each of which needs to be a `@Service`:
@Service
public class FizzAnalyticsService implements AnalyticsService {
@Override
public AnalyticsResult analyze(AnalyticsRequest request) {
// ...
}
}
@Service
public class BuzzAnalyticsService implements AnalyticsService {
@Override
public AnalyticsResult analyze(AnalyticsRequest request) {
// ...
}
}
// ... etc. (dozens)
I would like to create an `enum`, say, `AnalyticsType`:
public enum AnalyticsType {
FIZZ,
BUZZ,
... (dozens)
}
And somehow map/bind each enum value to a different `AnalyticsService` impl, such that a "client class" could select the correct impl at runtime, something like:
@Service
public class SomeService {
@Autowired
private FizzAnalyticsService fizzAnalyticsService;
@Autowired
private BuzzAnalyticsService buzzAnalyticsService;
// ... etc.
public void doSomthing(AnalyticsType type, AnalyticsRequest request) {
    AnalyticsService analyticsService = ??? (lookup by 'type')
    AnalyticsResult result = analyticsService.analyze(request);
}
}
What's the appropriate solution to do this type of lookup in Spring Boot?
</details>
# 答案1
**得分**: 1
以下是代码部分的翻译:
```java
public enum AnalyticsType {
    FIZZ,
    BUZZ
}
public class AnalyticsRequest {
    // 数据
}
public class AnalyticsResult {
    // 数据
}
public interface AnalyticsService {
    boolean supportsType(AnalyticsType analyticsType);
    AnalyticsResult analyze(AnalyticsRequest request);
}
@Service
public class FizzAnalyticsService implements AnalyticsService {
    @Override
    public boolean supportsType(final AnalyticsType analyticsType) {
        return AnalyticsType.FIZZ == analyticsType;
    }
    @Override
    public AnalyticsResult analyze(final AnalyticsRequest request) {
        return null;
    }
}
@Service
public class BuzzAnalyticsService implements AnalyticsService {
    @Override
    public boolean supportsType(final AnalyticsType analyticsType) {
        return AnalyticsType.BUZZ == analyticsType;
    }
    @Override
    public AnalyticsResult analyze(final AnalyticsRequest request) {
        return null;
    }
}
@Service
public class SomeService {
    private final List<AnalyticsService> analyticsServices;
    public SomeService(final List<AnalyticsService> analyticsServices) {
        this.analyticsServices = analyticsServices;
    }
    public void doSomthing(AnalyticsType type, AnalyticsRequest request) {
        AnalyticsService analyticsService = analyticsServices.stream()
                .filter(as -> as.supportsType(type))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("Type %s doesn't support analytics".formatted(type)));
        AnalyticsResult result = analyticsService.analyze(request);
    }
}
英文:
will something like this help you? You should be able to inject all services of same type to a collection and then by some criteria filter out those which you want.
public enum AnalyticsType {
    FIZZ,
    BUZZ
}
public class AnalyticsRequest {
    // data
}
public class AnalyticsResult {
    // data
}
public interface AnalyticsService {
    boolean supportsType(AnalyticsType analyticsType);
    AnalyticsResult analyze(AnalyticsRequest request);
}
@Service
public class FizzAnalyticsService implements AnalyticsService {
    @Override
    public boolean supportsType(final AnalyticsType analyticsType) {
        return AnalyticsType.FIZZ == analyticsType;
    }
    @Override
    public AnalyticsResult analyze(final AnalyticsRequest request) {
        return null;
    }
}
@Service
public class BuzzAnalyticsService implements AnalyticsService {
    @Override
    public boolean supportsType(final AnalyticsType analyticsType) {
        return AnalyticsType.BUZZ == analyticsType;
    }
    @Override
    public AnalyticsResult analyze(final AnalyticsRequest request) {
        return null;
    }
}
@Service
public class SomeService {
    private final List<AnalyticsService> analyticsServices;
    public SomeService(final List<AnalyticsService> analyticsServices) {
        this.analyticsServices = analyticsServices;
    }
    public void doSomthing(AnalyticsType type, AnalyticsRequest request) {
        AnalyticsService analyticsService = analyticsServices.stream()
                .filter(as -> as.supportsType(type))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("Type %s doesn't support analytics".formatted(type)))
        AnalyticsResult result = analyticsService.analyze(request);
    }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论