Sua ideia está no caminho certo.
Eu criaria 3 interfaces: PaymentMethod, PaymentRequest e PaymentResponse:
interface PaymentMethod {
PaymentResponse process(PaymentRequest request);
}
Assim cada tipo de pagamento teria sua implementação de PaymentMethod:
public class PixPayment implements PaymentMethod {
@Override
public PixPaymentResponse process(PaymentRequest request) {
PixPaymentRequest pixRequest = (PixPaymentRequest) request;
// Lógica para processar pagamento via PIX
return new PixPaymentResponse(/* parâmetros necessários */);
}
}
public class CreditCardPayment implements PaymentMethod {
@Override
public CreditCardPaymentResponse process(PaymentRequest request) {
CreditCardPaymentRequest ccRequest = (CreditCardPaymentRequest) request;
// Lógica para processar pagamento via Cartão de Crédito
return new CreditCardPaymentResponse(/* parâmetros necessários */);
}
}
public class BoletoPayment implements PaymentMethod {
@Override
public BoletoPaymentResponse process(PaymentRequest request) {
BoletoPaymentRequest boletoRequest = (BoletoPaymentRequest) request;
// Lógica para processar pagamento via Boleto
return new BoletoPaymentResponse(/* parâmetros necessários */);
}
}
Assim como cada tipo também teria suas respectivas implementações de PaymentRequest e PaymentResponse:
// PIX
public class PixPaymentRequest extends PaymentRequest {
private double amount;
// Getters e Setters
}
public class PixPaymentResponse extends PaymentResponse {
private String qrCode;
// Getters e Setters
}
// Cartão de Crédito
public class CreditCardPaymentRequest extends PaymentRequest {
private double amount;
private String cardNumber;
private String expirationDate;
private String cvv;
// Getters e Setters
}
public class CreditCardPaymentResponse extends PaymentResponse {
private boolean success;
private String transactionId;
// Getters e Setters
}
// Boleto
public class BoletoPaymentRequest extends PaymentRequest {
private double amount;
private String consumerName;
private String consumerCpf;
// Getters e Setters
}
public class BoletoPaymentResponse extends PaymentResponse {
private String boletoUrl;
// Getters e Setters
}
Você pode ter uma Factory para obter as instâncias de acordo com o tipo de pagamento:
public class PaymentMethodFactory {
public static PaymentMethod createPaymentMethod(PaymentType type) {
switch (type) {
case PIX:
return new PixPayment();
case CREDIT_CARD:
return new CreditCardPayment();
case BOLETO:
return new BoletoPayment();
default:
throw new IllegalArgumentException("Método de pagamento não suportado");
}
}
}
public enum PaymentType {
PIX, CREDIT_CARD, BOLETO;
}
A entidade Pagamento
deve ter campos comuns a todos os métodos de pagamento, além de um campo que identifique o tipo de método e possivelmente um campo JSON para armazenar dados específicos de cada método:
@Entity
public class Pagamento {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private double amount;
private String status;
private PaymentType paymentType;
@Lob
private String paymentDetails; // Armazena dados específicos de cada método como JSON
// Getters e Setters
}
O seu serviço de pagamentos poderia ter uma lógica assim:
public class PaymentService {
public PaymentResponse processPayment(PaymentType type, PaymentRequest request) {
PaymentMethod paymentMethod = PaymentMethodFactory.createPaymentMethod(type);
return paymentMethod.process(request);
}
}