2) Должен ли я всегда называть свой метод "визитом"?
Нет, метод имени более специфичен для конкретного домена.
1) Это неправильная реализация шаблона?
Глядя на вашу реализацию, я обнаружил, что она немного отличается.
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);
}
}
Одним из объектно-ориентированного программирования является инкапсуляция, когда объект должен своим данным (не подвергается воздействию извне).world).
С помощью шаблона Visitor мы можем предоставить дополнительную функциональность объекту, не раскрывая его данные снаружи.
Поскольку внутренние данные не отображаются снаружи объекта, посетителю необходимо «посетить объект», когда объект сможет предоставить посетителю требуемые значения, не раскрывая эти значения снаружи (не создавая эти значения).public).
В случае вопроса мы можем перевести калькулятор (посетителя) в класс CreditCard
, где калькулятор будет принимать только требуемые данные в качестве аргументов (обратите внимание только на требуемые значения - не на весь объект).
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
предоставляет данные (имеющие публичное свойство 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);
}
}