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);
    }
}