Выбор подходящего шаблона дизайна c# - PullRequest
0 голосов
/ 10 марта 2020

Мне поручено создать модуль оплаты, который состоит из различных типов способов оплаты.

Существуют различные типы объектов, которые могут go в каждом, которые могут незначительно изменить способ некоторые формулы рассчитаны. IE при наличии определенного имущества налог не взимается. Вот как я сейчас это делаю.

public abstract class Payment
{
    private readonly PersonToPay _personToPay;

    public Payment (PersonToPay personToPay)
    {
        _personToPay = personToPay;
    }

    public decimal PayFrom {get; set;}
    public decimal PayTo {get; set;}
    public decimal PayRate {get; set;}
    public decimal Gross {get; set;}
    public decimal Tax {get; set;}

    public void CalculateGross()
    {
        return PayRate * [days in period]
    }

    public void CalculateTax()
    {
        if (_personToPay.IsTypeOfX)
            Tax = 0;
        else
            Tax = PayRate * .1;
    }

    public virtual int GetDaysToPay()
    {
        int totalDays = 0;
        for (var x in _personToPay.ListOfItems)
        {
            if (x == someTypeOfValue)
                totalDays++;
        }

        return totalDays;
    }
}

Я пытаюсь взять все функциональные возможности этого класса и передать их другим классам, но так как все функциональные возможности привязаны к PersonToThePay объект, который вводится, как я могу сделать как таковой в производных классах? Примером может быть следующее:

public PaymentMethodA : Payment
{
    private readonly PersonToPay _personToPay;
    public PaymentMethodA(PersonToPay personToPay)
    {
        _personToPay = personToPay; // this personToPay would set the parent classes PersonToPay above to this
    }

    public int PaymentMethodAProperty;
    public override int GetDaysToPay()
    {
        return PaymentMethodAProperty * 2;
        //do PaymentMethodA logic here
    }
}

Я думал, что мог бы просто сделать PersonToPay свойством, но если вы не можете сделать платеж без получателя, разве не имеет смысла делать это? впрыснуть? Я также изучал шаблон стратегии для этого, но мне кажется, что шаблон имеет больше смысла. Хотя функциональность в значительной степени та же самая, сейчас я пытаюсь сделать ее максимально адаптируемой к изменениям, отсюда и отдельные классы.

Любое понимание того, что было бы лучше всего делать здесь, было бы очень полезно.

1 Ответ

2 голосов
/ 10 марта 2020

Здесь я вижу два вопроса: первый - это хороший шаблон. Это субъективно, но я бы также использовал шаблон стратегии. Что-то, что позволяет реализации быть чем-то, что не заботится о том, что это за платеж:

IPayment payment = new Payment() { PaymentAmount = 100 };
IPayment nonProfitPayment = new NonProfitPayment() { PaymentAmount = 100 };
Console.WriteLine($"Total for 100 payment: ${payment.TotalPayment()}");
Console.WriteLine($"Total for 100 payment: ${nonProfitPayment.TotalPayment()}");  

Что, конечно, дает: $ 106,00 и $ 100.

Определения классов:

public interface IPayment
{
    decimal TaxRate { get; set; }
    decimal PaymentAmount { get; set; }

    decimal TotalPayment();
}

public class Payment : IPayment
{
    public Payment()
    {
        TaxRate = 0.06M;
    }
    public decimal TaxRate { get; set; }
    public decimal PaymentAmount { get; set; }

    public decimal TotalPayment()
    {
        return PaymentAmount + (PaymentAmount * TaxRate);
    }
}

public class NonProfitPayment : Payment
{
    public NonProfitPayment()
    {
        TaxRate = 0;
    }
}

А затем по второму вопросу: получатель платежа и плательщик.

IMO это должны быть два дополнительных класса, передаваемых в класс / метод PostPayment. Быстрый псевдо-класс:

public class PostPayment: IPostPayment
{
    public PaymentResponse PostPayment(IPayee payee, IPayor payor, IPayment payment)
    {
        var totalPayment = payment.TotalPayment();
        var payorStatus = payor.Charge(totalPayment);
        if (payorStatus == ChargeStatus.InsuffucientFunds)
        {
           return PaymentResponse.InsuffificientCredit;
        }
        return payee.Credit(totalAmount).PaymentStatus;
    }
}

Это в конечном итоге гарантирует, что любые странные вещи для Типа вещи обрабатываются правильной вещью. Для дополнительных мыслей:

public class ReallyWeirdPayeeCase : IPayee
{
    public PaymentStatus Credit(decimal paymentAmount)
    {
         var approval = new ApprovalRequired()
         {
             ApprovalRequired = true,
             Amount = paymentAmount,
             DaysHoldRequired = 30
         };
         dbContext.CorporateApproval.Add(approvalRequired);
         return PaymentStatus.ThirtyDayApprovalQueued;
    }
}

Съемка с бедра но, я думаю, это показывает один хороший подход к рефакторингу существующего кода для Единой ответственности и удовлетворению ваших потребностей.

...