英文:
How to dynamically order the implementation list of a interface with default value in Spring Boot?
问题
我有一个扩展了 java.util.function.Function
的接口,有两个进一步的实现,假设是类 A 和 B,它们实现了接口 Base。
interface Base extends Function<Object, Object> {
@Override
default Object apply(Object object) {
return object; // 什么都不做
}
default boolean accept(String str) {
return true; // 用于选择正确的实例
}
}
@Service
class A implements Base {
String validationString = "some-random-string";
@Override
public Object apply(Object object) {
// 更新对象...
return object;
}
@Override
public boolean accept(String str) {
return str.equals(validationString);
}
}
@Service
class B implements Base {
String validationString = "some-random-string-2";
@Override
public Object apply(Object object) {
// 更新对象...
return object;
}
@Override
public boolean accept(String str) {
return str.equals(validationString);
}
}
@Service
@RequiredArgsConstructor
class SomeService {
List<Base> baseList;
public void callingClass(String str) {
// 在下面
// 我希望以这样的方式排序
// 如果 str 匹配 A.validationString,则返回 A 的实例
// 否则,如果 str 匹配 B.validationString,则返回 B 的实例
// 否则返回 Base 的实例
Base base = baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst().orElseThrow();
}
}
所以,我试图实现的目标是,是否有任何方法可以不必手动创建一个工厂类(工厂模式),并使用 accept() 动态过滤实例 A、B,如果找不到任何实例,则返回 Base 的实例。
有人可以帮忙吗?
英文:
I have an interface which extends java.util.function.Function
, there are 2 further implementation of the interface lets say class A, B which implements the interface Base;
interface Base extends Function<Object, Object> {
@Override
default Object apply(Object object) {
return object; // simply do nothing
}
default boolean accept(String str) {
return true; // for choosing the right instance
}
}
@Service
class A implements Base {
String validationString = "some-random-string";
@Override
public Object apply(Object object) {
// update the object ....
return object;
}
@Override
public boolean accept(String str) {
return str.equals(validationString);
}
}
@Service
class B implements Base {
String validationString = "some-random-string-2";
@Override
public Object apply(Object object) {
// update the object ....
return object;
}
@Override
public boolean accept(String str) {
return str.equals(validationString);
}
}
@Service
@RequiredArgsConstructor
class SomeService {
List<Base> baseList;
public void callingClass(String str) {
// in below
// I want to order it in such a way that
// if str matches A.validationString then give back A's instance
// else if str matches B.validationString then give back B's instance
// else return Base's instance
Base base = baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst().orElseThrow();
}
}
So, what I am trying to achieve, if there is any way from which I don't have to manually create a Factory Class (Factory Pattern) and dynamically Filter the instance A, B using accept() and if none find then return instance of Base (as default).
Can anybody help with this?
答案1
得分: 3
将@k314159和@atish.s的解决方案结合起来,并对其进行改进:
将DefaultBase类公开为另一个bean,但添加@Order注解以将其放置在列表的最后
@Component
@Order(Precedence.LAST)
class DefaultBase implements Base {
default accepts(Object obj){
return true;
}
}
然后将Service方法更改为以下内容:
public Base callingClass(String str) {
return baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst()
.orElseThrow();
}
英文:
Combining @k314159 and @atish.s solution and improving on that:
Expose the DefaultBase class as another bean, but add @Order annotation to put it last in list
@Component
@Order(Precedence.LAST)
class DefaultBase implements Base {
default accepts(Object obj){
return true;
}
}
Then changing the Service method to this:
public Base callingClass(String str) {
return baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst()
.orElseThrow();
}
答案2
得分: 1
// no need to annotate it with @service
// 无需用 @service 进行注解
class DefaultBase implements Base {
}
private static final Base DEFAULT_BASE = new DefaultBase();
public void callingClass(String str) {
Base base = baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst()
.orElseGet(DEFAULT_BASE);
}
英文:
You can do so by providing a default implementation for Base
as such;
// no need to annotate it with @service
class DefaultBase implements Base {
}
Then in your factory method,
private static final Base DEFAULT_BASE = new DefaultBase();
public void callingClass(String str) {
Base base = baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst()
.orElseGet(DEFAULT_BASE);
}
答案3
得分: 1
获取实现你的接口的服务类列表,并进行自动装配。
然后,创建一个默认的单个实例(可以是匿名类,或者像atish的回答中那样的命名类)。它不应该是一个Spring服务,因为你不希望它被包含在你的自动装配列表中。在你的方法中,如果找不到服务类,则返回这个默认实例。
@Service
@RequiredArgsConstructor
class SomeService {
private static final Base DEFAULT_BASE = new Base() {};
@Autowired
private List<Base> baseList;
public void callingClass(String str) {
Base base = baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst()
.orElse(DEFAULT_BASE);
}
}
英文:
Get the list of service classes implementing your interface by autowiring.
Then, create a single default instance (it can be an anonymous class, or a named class as in atish's answer). It must not be a Spring service as you don't want it to be included in your autowired list. In your method, if no service class is found, return this default instance.
@Service
@RequiredArgsConstructor
class SomeService {
private static final Base DEFAULT_BASE = new Base() {};
@Autowired
private List<Base> baseList;
public void callingClass(String str) {
Base base = baseList.stream()
.filter(baseImpl -> baseImpl.accept(str))
.findFirst()
.orElse(DEFAULT_BASE);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论