【问题标题】:How to use polymorphism with abstract spring service?如何使用抽象弹簧服务的多态性?
【发布时间】:2020-08-27 16:19:00
【问题描述】:

我有一个多态服务,像这样:

public abstract class PaymentService {
    abstract boolean processPayment(Payment payment);
}
@Service
public class CreditPaymentService extends PaymentService {
    @Override
    public boolean processPayment(Payment payment) {
        // method implementation
    }
}
@Service
public class CashPaymentService extends PaymentService {
    @Override
    public boolean processPayment(Payment payment) {
        // method implementation
    }
}

在我的 PaymentController 中,我收到了一笔付款,我必须将它发送到正确的服务来处理它,具体取决于付款的类型。

@Controller
public class PaymentController {

    @Autowired
    private PaymentService service;

    @Override
    @PostMapping
    public ResponseEntity<Payment> processPayment(@RequestBody Payment payment) {
        service.processPayment(payment);
        return noContent().build();
    }
}

spring 如何知道要实例化哪个服务?

【问题讨论】:

标签: java spring polymorphism autowired


【解决方案1】:

另一种方法是使用 bean 名称,如下所示。这需要请求中指定的付款方式。

示例:Payment

public class Payment {
    private String mode;

    public String getMode() {
        return this.mode;
    }

    //.. rest of the class
}

现在定义一个常量类PaymentModes

public final class PaymentModes {
    private PaymentModes() {
    }

    public static final String CASH = "cash";
    public static final String CREDIT = "credit";
}

并为服务提供 bean 名称

@Service(value = PaymentModes.CASH)
public class CashPaymentService extends PaymentService {

    @Override
    public boolean processPayment(Payment payment) {
        //Implementation
    }
}

@Service(value = PaymentModes.CREDIT)
public class CreditPaymentService extends PaymentService {
    @Override
    public boolean processPayment(Payment payment) {
        // Implementation
    }
}

这将使用组件扫描期间指定的 bean 名称将两个 bean 注册到应用程序上下文。

来自documentation

自动装配的 Map 实例的值由所有 bean 实例组成 匹配预期的类型,并且 Map 实例的键包含 对应的 bean 名称。

所以如果你按如下方式自动装配

@Autowired
Map<String,PaymentService> serviceMap;

地图如下:

{cash=rg.so.q61741320.CashPaymentService@1e74829, credit=rg.so.q61741320.CreditPaymentService@16f416f}

其中 key 是配置的 bean 名称,value 是 bean 实例。

以下逻辑可用于从地图中查找所需的服务实例。

@Override
@PostMapping
private ResponseEntity<Payment> processPayment(@RequestBody Payment payment) {
    String paymentMode = payment.getMode();// get payment mode;
    if(serviceMap.containsKey(paymentMode)) {
        serviceMap.get(paymentMode).processPayment(payment);
    }
    return noContent().build();
}

注意:被覆盖的方法应该是 public 以允许从其他类调用它,但在问题代码中以 private 给出。好像是笔误。

希望对你有帮助

【讨论】:

    【解决方案2】:

    对此有一种解决方法,即为您的支付服务使用工厂。

    首先创建一个工厂,它将根据 paymentType 为您提供正确的服务(您也可以为此使用 Enums)。

    然后,只要您想获得 paymentService,您就可以通过工厂获得它。

        @Component
        public class PaymentServiceFactory {
    
            @Autowired
            ApplicationContext context;
    
            public PaymentService getPaymentService(String paymentType) {
    
                // paymentType: Could be cash or credit
                return (PaymentService) context.getBean(paymentType + "PaymentService");
            }
        }
    
        @Controller
        public class PaymentController {
            @Autowired
            PaymentServiceFactory paymentServiceFactory;
    
            @PostMapping
            private ResponseEntity<Payment> processPayment(@RequestBody Payment payment) {
    
                PaymentService service = paymentServiceFactory.getPaymentService(payment.type);
                service.processPayment(payment);
                return noContent().build();
            }
        }
    

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

      不会的。您必须使用@Qualifier 并自动连接它们,然后确定将付款发送到哪一个,大概是通过查看请求正文。

      【讨论】:

        猜你喜欢
        • 2017-02-16
        • 2015-01-20
        • 1970-01-01
        • 2019-05-17
        • 2018-01-24
        • 1970-01-01
        • 2013-08-13
        • 2020-02-16
        • 1970-01-01
        相关资源
        最近更新 更多