繁体   English   中英

在类 C# 中使用两个构造函数时如何避免代码重复

[英]How to avoid duplication of code when using two constructors in a class C#

大家好,我有两个请求 DTO,其中一个是父级,一个是子级。

    public class PaymentSupplierPaymentRequest
{
    [JsonProperty("description")]
    public string Description { get; set; }

    [JsonProperty("amount")]
    [Required]
    public decimal Amount { get; set; }

    [JsonProperty("currency")]
    public string Currency { get; set; }

    [JsonProperty("supplierid")]
    [Required]
    public string SupplierId { get; set; }

    [JsonProperty("accountid")]
    [Required]
    public long AccountId { get; set; }
}

public class PaymentSupplierLitePaymentRequest: PaymentSupplierPaymentRequest
{
    [JsonProperty("merchantCode")]
    [Required]
    public string MerchantCode { get; set; }
}

支付请求有两种类型,一种是需要商户代码的,一种是不需要商户代码的。 根据请求,我有另一个类,它使用两个构造函数来处理传递给请求的数据。

    private readonly string _merchantCode;
    private readonly string _installationId;
    private readonly string _version;
    private readonly string _paymentMethodMaskCode;
    private readonly string _orderDescription;
    private readonly long _amount;
    private readonly string _currency;
    private readonly string _email;
    private const byte Exponent = 2;
    private readonly string _orderCode;

        public GemPayPaymentRequestBuilder(PaymentSupplierLitePaymentRequest paymentRequest)
    {
        _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
        _orderDescription = paymentRequest.Description;
        _currency = paymentRequest.Currency;
        _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";
        _merchantCode = paymentRequest.MerchantCode;
    }

    public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest, string email, WorldPayMerchantConfig config)
    {
        _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
        _orderDescription = paymentRequest.Description;
        _currency = paymentRequest.Currency;
        _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";
        _email = email;
        _merchantCode = config.MerchantCode;
        _installationId = config.InstallationId;
        _version = config.Version;
        _paymentMethodMaskCode = config.PaymentMethodMaskCode;
    }

正如您在代码中看到的那样,问题是我在两个构造函数中复制了某些局部变量的初始化。

        _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
        _orderDescription = paymentRequest.Description;
        _currency = paymentRequest.Currency;
        _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";

有没有人有更清洁的方法来做到这一点? 我尝试对第二个构造函数使用构造函数继承,如下所示。

       public GemPayPaymentRequestBuilder(PaymentSupplierLitePaymentRequest paymentRequest)
    {
        _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
        _orderDescription = paymentRequest.Description;
        _currency = paymentRequest.Currency;
        _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";
        _merchantCode = paymentRequest.MerchantCode;
    }

    public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest, string email, WorldPayMerchantConfig config) : this(paymentRequest)
    {
        _email = email;
        _merchantCode = config.MerchantCode;
        _installationId = config.InstallationId;
        _version = config.Version;
        _paymentMethodMaskCode = config.PaymentMethodMaskCode;
    }

但这在使用时不起作用: this(paymentRequest)会引发转换错误,因为它无法从 PaymentSupplierPaymentRequest 转换为 PaymentSupplierLitePaymentRequest。 有任何想法吗?

仅使用构造函数。

最简单的方法是调用: this从不同的构造函数(因为PaymentSupplierLitePaymentRequest继承PaymentSupplierPaymentRequest ,反之亦然),但是您需要在第二个构造函数中处理其他参数并稍微更改代码:

public GemPayPaymentRequestBuilder(PaymentSupplierLitePaymentRequest paymentRequest) : this(paymentRequest, null, null)
{
    _merchantCode = paymentRequest.MerchantCode;
}

public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest, string email, WorldPayMerchantConfig config)
{
    _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
    _orderDescription = paymentRequest.Description;
    _currency = paymentRequest.Currency;
    _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";

    _email = email;

    if (config != null)
    {
        _merchantCode = config.MerchantCode;
        _installationId = config.InstallationId;
        _version = config.Version;
        _paymentMethodMaskCode = config.PaymentMethodMaskCode;
    }
}

或另一种方法-您可以创建非公共构造函数来初始化公共数据并从公共数据中调用它(代码比上述方法更干净(我认为),并且您有单独的位置来初始化没有null s和if s的公共属性) :

// protected (only for common data) and PaymentSupplierPaymentRequest as parameter
protected GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest) 
{
    _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
    _orderDescription = paymentRequest.Description;
    _currency = paymentRequest.Currency;
    _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";
}

public GemPayPaymentRequestBuilder(PaymentSupplierLitePaymentRequest paymentRequest) : this((PaymentSupplierPaymentRequest)paymentRequest)
{
    _merchantCode = paymentRequest.MerchantCode;
}

public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest, string email, WorldPayMerchantConfig config) : this(paymentRequest)
{
    _email = email;
    _merchantCode = config.MerchantCode;
    _installationId = config.InstallationId;
    _version = config.Version;
    _paymentMethodMaskCode = config.PaymentMethodMaskCode;
}

使用单独的方法。

您可以创建单独的方法,该方法将包含两种类型相同的逻辑:

private void InitializeCommonData(PaymentSupplierPaymentRequest paymentRequest)
{
    _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
    _orderDescription = paymentRequest.Description;
    _currency = paymentRequest.Currency;
    _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";
}

然后你可以初始化属性/字段:

public GemPayPaymentRequestBuilder(PaymentSupplierLitePaymentRequest paymentRequest)
{
    this.InitializeCommonData(paymentRequest);
    _merchantCode = paymentRequest.MerchantCode;
}

public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest, string email, WorldPayMerchantConfig config)
{
    this.InitializeCommonData(paymentRequest);
    _email = email;
    _merchantCode = config.MerchantCode;
    _installationId = config.InstallationId;
    _version = config.Version;
    _paymentMethodMaskCode = config.PaymentMethodMaskCode;
}

您可以始终传递基类并始终调用完整的构造函数:

    public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest)
        : this(paymentRequest, null, null)
    {
    }

    public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest, string email, WorldPayMerchantConfig config)
    {
        _amount = (long)(paymentRequest.Amount * (decimal)Math.Pow(10, Exponent));
        _orderDescription = paymentRequest.Description;
        _currency = paymentRequest.Currency;
        _orderCode = $"{paymentRequest.AccountId}_{DateTime.UtcNow.Ticks}";
            
        _email = email;

        var liteRequest = paymentRequest as PaymentSupplierLitePaymentRequest;
        if (liteRequest != null)
        {
            _merchantCode = liteRequest.MerchantCode;
        }
        else if (config != null)
        {
            _merchantCode = config.MerchantCode;
        }

        if (config != null)
        {
            _installationId = config.InstallationId;
            _version = config.Version;
            _paymentMethodMaskCode = config.PaymentMethodMaskCode;
        }
    }
}

在完整的构造函数(管理所有可能参数的构造函数)中,您可以尝试转换您的类。 如果类是 Lite,则设置它的属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM