c# - 自定义访客模式实现

标签 c# design-patterns interface visitor-pattern

我正在尝试实现一种访问者模式。 Web 上的大多数示例都显示了一个带有“访问”方法和该方法的多个重载的访问者类。在这种情况下,我将我的“访问”方法称为 CalculateFee(这是一个语义问题)及其重载。到目前为止一切正常,但现在我需要再次实现访问者以执行另一个方法“CalculateExtraCharge”,因此我添加了另一个名为 CalculateExtraCharge 的方法及其重载。但是现在我有两个问题

1) 这是模式的错误实现吗?

2) 我应该总是称我的方法为“访问”吗?

这是我的代码的概述,我省略了其中的一些部分以仅关注对我的问题重要的部分。

    public class CreditCard : IPaymentMethod
    {
        public decimal Amount { get; set; }

        public decimal GetFee(IPaymentCalculationsVisitor visitor)
        {
            return visitor.CalculateFee(this);
        }

        public decimal GetExtraCharge(IPaymentCalculationsVisitor visitor)
        {
            return visitor.CalculateExtraCharge(this);
        }

    }

    public class Check : IPaymentMethod
    {
        public decimal Amount { get; set; }

        public decimal GetFee(IPaymentCalculationsVisitor visitor)
        {
            return visitor.CalculateFee(this);
        }

        public decimal GetExtraCharge(IPaymentCalculationsVisitor visitor)
        {
            return visitor.CalculateExtraCharge(this);
        }
    }

    public interface IPaymentCalculationsVisitor
    {
        decimal CalculateFee(CreditCard creditCard);
        decimal CalculateFee(Check check);

        decimal CalculateExtraCharge(CreditCard creditCard);
        decimal CalculateExtraCharge(Check check);
    }

    public class PaymentCalculationsVisitor: IPaymentCalculationsVisitor
    {

        public decimal CalculateFee(CreditCard creditCard)
        {
            return creditCard.Amount * 0.15m;

        }

        public decimal CalculateFee(Check check)
        {
            return check.Amount * 0.10m;
        }

        public decimal CalculateExtraCharge(CreditCard creditCard)
        {
            return 15;
        }

        public decimal CalculateExtraCharge(Check check)
        {
            return 10;
        }

    }

    public class PaymentProcessor
    {

        public void ProcessPayment()
        {
            var paymentMethods = new List<IPaymentMethod>()
            {
                new CreditCard(),
                new Check()
            };

            var calculationsVisitor = new PaymentCalculationsVisitor();

            foreach (var paymentMethod in paymentMethods)
            {

                //First i need to get the fee
                var fee = paymentMethod.GetFee(calculationsVisitor);

                //Then i do do some other stuff, validations, other calculations etc

                //Finally i get the extra charge
                var extraCharge = paymentMethod.GetExtraCharge(calculationsVisitor);
            }

        }

    }

最佳答案

2) Should i always call my method "visit"?

不,以更特定领域的方式命名方法。

1) Is this a wrong implementation of the pattern?

查看您的实现,我发现它有点不同。

public class CreditCard : IPaymentMethod
{
    public decimal Amount { get; set; }

    public decimal GetFee(IPaymentCalculationsVisitor visitor)
    {
        return visitor.CalculateFee(this);
    }

    public decimal GetExtraCharge(IPaymentCalculationsVisitor visitor)
    {
        return visitor.CalculateExtraCharge(this);
    }
}

面向对象的编程之一是封装,其中对象拥有其数据(不暴露给外界)。
使用访问者模式,我们可以为对象提供额外的功能,而无需将其数据暴露在外部。

因为内部数据没有暴露给对象的外部,访问者需要“访问对象内部”,对象将能够向访问者提供所需的值,而不会将这些值暴露在外部(不公开这些值)。

对于问题的情况,我们可以将 calculator(visitor) 传递给 CreditCard 类,其中 calculator 将只接受必需的数据作为参数(注意只需要必需的值 - 而不是整个对象)。

public class CreditCard : IPaymentMethod
{
    // Following OOP principles and keep data private
    private decimal _amount;

    public CreditCard(decimal amount) => _amount;

    public decimal GetFee(IPaymentCalculationsVisitor visitor)
    {
        return visitor.CalculateFee(_amount); // provide only required data
    }

    public decimal GetExtraCharge(IPaymentCalculationsVisitor visitor)
    {
        return visitor.CalculateExtraCharge(_amount); // provide only required data
    }
}

使用这种方法,计算器(访问者)类将不依赖于它可以访问的类。实际上它可以访问任何可以提供所需信息的类。

在您的特定情况下,CreditCard 公开数据(具有公共(public)属性 Amount)- 您可以删除冗余步骤并将信用卡对象直接传递给计算

 public void ProcessPayment()
 {
     var paymentMethods = new List<IPaymentMethod>()
     {
            new CreditCard(),
            new Check()
     };

     var calculations = new PaymentCalculationsVisitor();

     foreach (var paymentMethod in paymentMethods)
     {
        //First i need to get the fee
        var fee = calculations.GetFee(paymentMethod);

        //Then i do do some other stuff, validations, other calculations etc

        //Finally i get the extra charge
        var extraCharge = calculations.GetExtraCharge(paymentMethod);
    }
}

关于c# - 自定义访客模式实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54770203/

相关文章:

c# - ASP.net 中的静态文件和身份验证

java - 如何在方法中使用带有 "fallback"参数的接口(interface)?

java - 我如何组织和减少申请中的类(class)数量

design-patterns - 如何使用变量名称而不覆盖模块名称?

c# - 在 C# 中实现 IUnknown

java - 如何从 jython 中的 java 类获取接口(interface)列表?

c# - 使用所有备份集通过 SMO 恢复数据库

c# - 如何用BingMap计算 map 4个角(边)的坐标?

c++ - Java 的最佳方法,如 C++ 中的适配器事件处理

c# - .NET 类型推断 : can't infer usage of "T GetValue<T>(T defaultValue = default(T))"?