如何在Spring Boot中动态排序具有默认值的接口实现列表?

huangapple go评论67阅读模式
英文:

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&lt;Object, Object&gt; {

  @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 = &quot;some-random-string&quot;;

  @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 = &quot;some-random-string-2&quot;;

  @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&lt;Base&gt; 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&#39;s instance
    // else if str matches B.validationString then give back B&#39;s instance
    // else return Base&#39;s instance
    Base base = baseList.stream()
        .filter(baseImpl -&gt; 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 -&gt; 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 -&gt; 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&lt;Base&gt; baseList;

  public void callingClass(String str) {

    Base base = baseList.stream()
        .filter(baseImpl -&gt; baseImpl.accept(str))
        .findFirst()
        .orElse(DEFAULT_BASE);

  }
}

huangapple
  • 本文由 发表于 2023年6月12日 21:30:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76457174.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定