[英]Custom visitor pattern implementation
我正在嘗試實現一種訪客模式。 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)我應該始終將我的方法稱為“訪問”嗎?
否,以更特定於域的方式命名方法。
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);
}
}
面向對象編程之一是封裝,其中對象欠其數據(不暴露給外界)。
使用Visitor模式,我們可以為對象提供額外的功能,而無需將其數據暴露在外部。
由於內部數據沒有暴露給對象的外部,因此訪問者需要“訪問對象內部”,其中對象將能夠向訪問者提供所需的值,而不會在外部暴露這些值(而不會公開這些值)。
對於問題的情況,我們可以將CreditCard
(visitor)傳遞到CreditCard
類中,在該類中, 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);
}
}
1)這是該模式的錯誤實現嗎?
不,這仍然是GoF訪客模式。 IPaymentCalculationsVisitor
訪問兩種不同方法的能力不會改變模式的性質。 因為它結合了兩次不同訪問的邏輯,所以您可能要考慮SOLID原則。
CalculateFee
和CalculateExtraCharge
解耦,因此客戶端可以擁有一個而沒有另一個。 請注意,訪問者模式可以允許將新行為添加到IPaymentMethod
類型層次結構中,而無需修改子類(例如CreditCard
和Check
。 通過將訪問者界面分為FeeVisitor
和ExtraChargeVisitor
,可以將兩者都傳遞到單個訪問方法中。
2)我應該始終將我的方法稱為“訪問”嗎?
不,在任何設計模式下,您都可以根據自己的喜好命名方法。 最重要的是,代碼對您及其領域具有意義。 為了與其他開發人員共同使用詞匯,如果您認為可以澄清代碼的意圖,則可以考慮使用該模式的已發布術語添加文檔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.