gpt4 book ai didi

java - 基于运行时提供的字符串查找要使用哪个接口(interface)实现的优雅解决方案

转载 作者:搜寻专家 更新时间:2023-10-31 20:34:20 25 4
gpt4 key购买 nike

在重构一些代码时,我发现我们应该在几个地方使用一些多态性,而不是到处都有一堆 if/else block 。

虽然面向对象的类很容易制作,但当我们必须决定使用什么实现时,问题就来了。似乎有很多解决方案,但我想看看是否有更优雅或“最佳实践”的方法来做到这一点。

所以基本上,为了举例,我将选择一张信用卡,并且对于每种信用卡类型,我都有一个实现。因此我有一个这样的类结构:

  • 信用卡(摘要)
    • 签证
    • 万事达卡
    • 美国运通卡

每个子类都将扩展 CreditCard 父类(super class)。

现在在 Web 应用程序中,我将传递一个表示用户选择的卡片类型的字符串。现在我需要将它路由到实际的实现类本身。这就是过多选择发挥作用的地方。

如果有更好的选择或者我是否坚持使用这些选择,请务必告诉我..

工厂:

        @Autowired @Qualifier("visa") private CreditCard visa;
@Autowired @Qualifier("mastercard") private CreditCard mastercard;
@Autowired @Qualifier("amex") private CreditCard amex;

public CreditCard getCreditCard(String input) {
{
if ("visa".equals(input)) {
return visa;
} else if ("mastercard".equals(input)) {
return mastercard;
} else if ("amex".equals(input)) {
return amex;
}

return null;
}

map :

        @Autowired HashMap<String, CreditCard> creditCardImpls;

public CreditCard getCreditCard(String input) {
return creditCardImpls.get(input);
}

ApplicationContext getBean:

        @Autowired private ApplicationContext applicationContext;

public CreditCard getCreditCard(String input) {
return applicationContext.getBean(input);
}

我在这里看到的问题是,如果我们要在未来添加更多的信用卡类型,我将不得不在可能的几个不同领域 Autowiring 。然后,Map 的问题是我们没有使用 Spring 来获取 bean。对于吨他从 ApplicationContext 中获取 Bean,我们没有遵循 Spring 提供的 IoC。

这个问题的最佳解决方案或最佳实践是什么?

最佳答案

首先对您的解决方案发表一些评论,然后是我自己的建议。

  1. 这违反了 Open-Closed PrincipleDependency Inversion Principle .不仅工厂需要明确知道所有的 bean 分别和它们对应的信用卡类型(input)映射,而且每次你​​想引入一个新的信用卡类型时,你需要修改工厂类代码。
  2. 这是迄今为止您最好的解决方案,IMO。它动态地发现 bean 并依赖于 CreditCard抽象。与您的评论“它不使用 Spring 来确定要使用哪个 bean”相反,该映射将 bean ID 作为键并由 Spring Autowiring ,因此我们实际上在这里广泛使用了 Spring。但是,由于映射键是 bean ID,这将业务逻辑(信用卡类型 - input)与技术实现(Spring bean ID)混合在一起。如果你想实现一个单独的 bean 来处理“mastercard platinum”信用卡类型怎么办?由于技术原因,您不能拥有这样的 bean ID(由于空间)。或者在某些时候您会希望某个 bean 可以处理多种卡片类型。然后,您需要在业务标识符和 bean ID 之间实现另一个转换映射。请参阅下面我的解决方案以获得增强功能。
  3. 您应该尽可能避免将您的代码与框架代码(Spring 或任何其他代码)耦合。正如您所说,我们应该让 Spring 为我们处理 DI,这样工厂类就会注入(inject)依赖项,而不必显式请求它们。

我的建议是将业务 key 与 bean ID 分开。所以我们需要 CreditCard能够说明它可以处理哪种信用卡类型。

abstract class CreditCard {
public abstract String getType();
}

然后每个子类返回自己的类型。

或者

abstract class CreditCard {
private String type;

protected CreditCard(String type) {
this.type = type;
}

public String getType() {
return type;
}
}

每个子类调用super(<the subclass type>)他们自己的构造函数中的构造函数。

然后,在工厂中,您可以这样实现。

@Autowire private Collection<CreditCard> creditCards;

private Map<String, CreditCard> creditCardsMap = new HashMap<>();

@PostCostruct
public void mapCreditCards() {
for (CreditCard creditCard : creditCards) {
creditCardsMap.put(creditCard.getType(), creditCard);
}
}

public CreditCard getCreditCard(String type) {
return creditCardsMap.get(type);
}

@PostConstruct方法将在 creditCards 之后运行(所有类型为 CreditCard 的 bean)都已 Autowiring ,因此允许在业务 key 而非技术 key 下进行动态发现和映射。

关于java - 基于运行时提供的字符串查找要使用哪个接口(interface)实现的优雅解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23507079/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com