如何在C#最佳面向对象风格中调用适当的计算类方法?

如何在C#最佳面向对象风格中调用适当的计算类方法?,c#,C#,我有一个类AnnuityContext,其中包含贷款年金支付的数据。 Сlass包含以两种方式计算年金支付的方法-相等和差异支付-计算差异和计算相等 public class AnnuityContext : INotifyPropertyChanged { //... internal void CalculationDifferential() { //... } internal void CalculationEqual()

我有一个类AnnuityContext,其中包含贷款年金支付的数据。 Сlass包含以两种方式计算年金支付的方法-相等和差异支付-计算差异和计算相等

public class AnnuityContext : INotifyPropertyChanged
{
    //...

    internal void CalculationDifferential()
    {
      //...
    }

    internal void CalculationEqual()
    {
      //...
    }

}
主页有组合框和按钮。按下按钮时,根据组合框选择,将调用相应的方法:

private void buttonCalculation_Click(object sender, RoutedEventArgs e)
{
    if (flag == 1)
      this.AnnuityData.CalculationDifferential();
    else
      this.AnnuityData.CalculationEqual();
}
我的问题是如何以更面向对象的方式执行相同的任务。可能是从函数CalculationDifferential()和CalculationQual()创建方法计算和调用


我将使用继承和多态性:

void Main()
{
    Process(new DifferentialAnnuityContext());
    Process(new EqualAnnuityContext());
}

public static void Process(AnnuityContext context)
{
    context.Calculate();
}

public abstract class AnnuityContext
{
    public abstract void Calculate();
}

public class DifferentialAnnuityContext : AnnuityContext
{
    public override void Calculate()
    {
        Debug.WriteLine("Differential");
    }
}

public class EqualAnnuityContext : AnnuityContext
{
    public override void Calculate()
    {
        Debug.WriteLine("Equal");
    }
}
您可以看到,
Process
方法既不知道也不关心调用它的两种(或更多)类型中的哪一种

这样就不需要调用计算的代码来知道调用哪一个,因为只有一个


你可以在

中测试上面的程序。如果你真的认为你要为计算创建不同的公式,你可以考虑一个“计算对象”,让UI选择一个使用。p> 您可以(至少)通过两种方式创建此类对象:

  • 为计算定义基类。这实际上就是“模板”模式。比如:
  • 公共类贷款计算器库 {

    受保护的双性能计算驱动(InputData) { //在派生类中重写此 }

    公共双性能计算(输入数据) { 性能计算驱动(数据); }

    }

    注意:您还可以将PerformCalculation设置为要重写的类。如果您有一个函数需要计算(可管理的部分),则应该考虑计算的每个“部分”的重写。如果它很简单,只需重写单个函数即可。通过基类有效地定义了函数的接口。在运行时,您创建一个派生类的实例,但使用基类指针

    注意:您还可以使类抽象(无实现)或使PerformCalculationBase(…)抽象(因此派生程序被迫实现某些东西)

  • 使用接口。这定义了其他类如何访问您的计算器,但没有定义任何关于计算器内部的内容(主要是)。然后您只需要创建一个满足接口要求的计算器。不使用基类指针,而是使用接口指针来访问它
  • 公共接口计算器 { 受保护的双性能计算驱动(输入数据); }

    在你的课堂上保留一份iCalculator参考资料。初始化为默认情况下要使用的任何计算的实例(必须继承/实现ICalculator),并在用户选择新计算时根据需要进行更改。那么就这样称呼它:

    //课堂上 专用ICalculator calc=null

    //在功能上: 结果=计算值(数据)

    你选择哪种方式可能会有,也可能不会有深入的讨论。我更喜欢接口,因为它们更关注于您想要提供的东西(合同)

    C#将允许您为派生类定义多个接口,但只能定义一个基类


    这有用吗?

    我决定使用一个抽象类来创建一个负责选择年金公式的对象

    #region CalculationFormula implementation
    public abstract class CalculationFormulaBase
    {
        public abstract List<AnnuityPayment> Execute(AnnuityContext context);
    }
    
    public class CalculationFormulaDifferential : CalculationFormulaBase
    {
        public override List<AnnuityPayment> Execute(AnnuityContext context)
        {
            decimal refundPrincipal = (decimal)context.PrincipalAmount / context.LoanTerm;
            double monthlyRate = (double)context.InterestRate / 12 / 100;
    
            decimal loanBalance = context.PrincipalAmount;
    
            List<AnnuityPayment> annuityPayments = new List<AnnuityPayment>(context.LoanTerm + 1);
            for (int i = 0; i < context.LoanTerm; i++)
            {
                decimal refundInterest = loanBalance * Convert.ToDecimal(monthlyRate);
    
                loanBalance = loanBalance - refundPrincipal;
    
                annuityPayments.Add(new AnnuityPayment { Period = String.Format("{0:#}", i + 1), RefundPrincipal = refundPrincipal, RefundInterest = refundInterest, MonthlyPayment = refundPrincipal + refundInterest, LoanBalance = loanBalance });
            }
    
            return annuityPayments;
        }
    }
    
    public class CalculationFormulaEqual : CalculationFormulaBase
    {
        public override List<AnnuityPayment> Execute(AnnuityContext context)
        {
            double monthlyRate = (double)context.InterestRate / 12 / 100;
    
            double coefficient = monthlyRate / (1 - Math.Pow(1 + monthlyRate, -context.LoanTerm));
            decimal refundAnnuity = (decimal)context.PrincipalAmount * Convert.ToDecimal(coefficient);
    
            decimal loanBalance = context.PrincipalAmount;
    
            List<AnnuityPayment> annuityPayments = new List<AnnuityPayment>(context.LoanTerm + 1);
            for (int i = 0; i < context.LoanTerm; i++)
            {
                decimal refundInterest = loanBalance * Convert.ToDecimal(monthlyRate);
    
                decimal refundPrincipal = refundAnnuity - refundInterest;
    
                loanBalance = loanBalance - refundPrincipal;
    
                annuityPayments.Add(new AnnuityPayment { Period = String.Format("{0:#}", i + 1), RefundPrincipal = refundPrincipal, RefundInterest = refundInterest, MonthlyPayment = refundPrincipal + refundInterest, LoanBalance = loanBalance });
            }
    
            return annuityPayments;
        }
    }
    #endregion
    
    当页面在Silverlight中初始化时,我设置了计算年金的defait公式:

    public MainPage()
    {
        InitializeComponent();
    
        this.AnnuityData = new AnnuityContext { VehiclePrice = 500000, DownPaymentPercent = 20, LoanTerm = 36, InterestRate = 15, Summ = 600000, PeriodsCount = 60, RateString = "16" };
        sliderPrincipalAmount.Value = 400000;
    
        //this.AnnuityData.CalculationFormula = new CalculationFormulaDifferential();
        this.AnnuityData.CalculationFormula = new CalculationFormulaEqual();
    
    
        this.DataContext = this.AnnuityData;
    
        buttonCalculation.Focus();
    }
    

    这实际上取决于CalculationDifferential和CalculationEqual的实现。从MSDN文档
    只能在同一程序集中的文件中访问内部类型或成员。也许您假设它在某种程度上等同于内部类。
    
    public class AnnuityContext : INotifyPropertyChanged
    {
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void NotifyPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
            private IList<AnnuityPayment> m_AnnuityPayments = new List<AnnuityPayment>();
            public IEnumerable<AnnuityPayment> AnnuityPayments
            {
                get
                {
                    return m_AnnuityPayments;
                }
            }
    
            private CalculationFormulaBase m_CalculationFormula;
            public CalculationFormulaBase CalculationFormula
            {
                get { return m_CalculationFormula; }
                set
                {
                    if (m_CalculationFormula != value)
                    {
                        m_CalculationFormula = value;
    
                        EmptyAnnuityPayments();
                    }
                }
            }
    
          //...
       }
    
    internal void Calculation()
    {
        m_AnnuityPayments = CalculationFormula.Execute(this);
    
        NotifyPropertyChanged("AnnuityPayments");
    
        //...
    }
    
    public MainPage()
    {
        InitializeComponent();
    
        this.AnnuityData = new AnnuityContext { VehiclePrice = 500000, DownPaymentPercent = 20, LoanTerm = 36, InterestRate = 15, Summ = 600000, PeriodsCount = 60, RateString = "16" };
        sliderPrincipalAmount.Value = 400000;
    
        //this.AnnuityData.CalculationFormula = new CalculationFormulaDifferential();
        this.AnnuityData.CalculationFormula = new CalculationFormulaEqual();
    
    
        this.DataContext = this.AnnuityData;
    
        buttonCalculation.Focus();
    }