Oop 重构在向类型添加方法时打开类型代码气味似乎不合适
假设我有以下方法,在给定PaymentType的情况下,将适当的付款请求发送到每个需要提取付款的贷款机构:Oop 重构在向类型添加方法时打开类型代码气味似乎不合适,oop,polymorphism,refactoring,Oop,Polymorphism,Refactoring,假设我有以下方法,在给定PaymentType的情况下,将适当的付款请求发送到每个需要提取付款的贷款机构: public void SendRequestToPaymentFacility(PaymentType payment) { if(payment is CreditCard) { SendRequestToCreditCardProcessingCenter(); } else if(payment is BankAccount) { Send
public void SendRequestToPaymentFacility(PaymentType payment) {
if(payment is CreditCard) {
SendRequestToCreditCardProcessingCenter();
} else if(payment is BankAccount) {
SendRequestToBank();
} else if(payment is PawnTicket) {
SendRequestToPawnShop();
}
}
显然,这是一种代码味道,但在寻找适当的重构时,我看到的唯一示例涉及在条件中执行的代码显然是类本身的责任的情况,例如,给出的标准示例:
public double GetArea(Shape shape) {
if(shape is Circle) {
Circle circle = shape As Circle;
return circle.PI * (circle.radius * circle.radius);
} else if(shape is Square) {
Square square = shape as Square;
return square.length * square.width;
}
}
GetArea()
似乎是每个形状子类的合理职责,当然可以很好地重构:
public class Shape
{
/* ... */
public abstract double GetArea();
}
public class Circle
{
public override double GetArea()
{
return PI * (radius * radius);
}
}
但是,
SendRequestToPaymentFacility()
似乎不是PaymentType
的适当责任。(而且似乎违反了单一责任原则)。但我需要根据“<代码> PaymentType < /代码>的类型向适当的<代码>支付工具< /代码>发送一个请求-最好的方法是什么? 你可以考虑添加一个属性或方法到你的代码> ChanyBar 类中,它指示烛台是否包含坚果。现在,您的GetProcessingPlant()
方法不必了解不同类型的烛台
public ProcessingPlant GetProcessingPlant(CandyBar candyBar) {
if(candyBar.ContainsNuts) {
return new NutProcessingPlant();
} else {
return new RegularProcessingPlant();
}
}
一个选项是将IPaymentFacility接口参数添加到各个PaymentType子体的构造函数中。基本PaymentType可以具有抽象PaymentFacility属性;基本类型上的SendRequestToPaymentFacility将委托:
public abstract class PaymentType
{
protected abstract IPaymentFacility PaymentFacility { get; }
public void SendRequestToPaymentFacility()
{
PaymentFacility.Process(this);
}
}
public interface IPaymentFacility
{
void Process(PaymentType paymentType);
}
public class BankAccount : PaymentType
{
public BankAccount(IPaymentFacility paymentFacility)
{
_paymentFacility = paymentFacility;
}
protected override IPaymentFacility PaymentFacility
{
get { return _paymentFacility; }
}
private readonly IPaymentFacility _paymentFacility;
}
您可以使用DI/IoC容器库,而不是手动连接依赖项注入。对其进行配置,使银行帐户获得银行等
缺点是,支付工具只能访问基本类PaymentType的公共(或可能是内部)成员
编辑:
实际上,您可以使用泛型获取子类成员。要么将SendRequestToPaymentFacility设置为抽象(去掉抽象属性),要么选择:
public abstract class PaymentType<TPaymentType>
where TPaymentType : PaymentType<TPaymentType>
{
protected abstract IPaymentFacility<TPaymentType> PaymentFacility { get; }
public void SendRequestToPaymentFacility()
{
PaymentFacility.Process((TPaymentType) this);
}
}
public class BankAccount : PaymentType<BankAccount>
{
public BankAccount(IPaymentFacility<BankAccount> paymentFacility)
{
_paymentFacility = paymentFacility;
}
protected override IPaymentFacility<BankAccount> PaymentFacility
{
get { return _paymentFacility; }
}
private readonly IPaymentFacility<BankAccount> _paymentFacility;
}
public interface IPaymentFacility<TPaymentType>
where TPaymentType : PaymentType<TPaymentType>
{
void Process(TPaymentType paymentType);
}
public class Bank : IPaymentFacility<BankAccount>
{
public void Process(BankAccount paymentType)
{
}
}
公共抽象类PaymentType
其中TPaymentType:PaymentType
{
受保护的抽象IPaymentFacility PaymentFacility{get;}
公共作废SendRequestToPaymentFacility()
{
PaymentFacility.Process((TPaymentType)此);
}
}
公共类银行账户:PaymentType
{
公共银行账户(IPaymentFacility paymentFacility)
{
_paymentFacility=paymentFacility;
}
受保护的覆盖IPaymentFacility PaymentFacility
{
获取{return\u paymentFacility;}
}
私人只读IPaymentFacility\u支付设施;
}
公共接口IPaymentFacility
其中TPaymentType:PaymentType
{
作废流程(TPaymentType paymentType);
}
公共类银行:IPaymentFacility
{
公共作废流程(银行账户付款类型)
{
}
}
这里的缺点是将银行耦合到BankAccount类
此外,他还提出了一些很好的观点。这里可以采用的一种方法是使用命令模式。在这种情况下,您将创建并排队执行相应的命令(例如,信用卡、银行帐户、当票),而不是调用特定的方法。然后,您可以为每个执行适当操作的命令使用单独的命令处理器 如果您不希望这里的条件复杂性,您可以提出一种将支付类型作为属性包含在内的命令类型,然后命令处理者可以负责确定如何处理该请求(使用适当的支付处理者)
这两种方法中的任何一种都可以帮助你的学生将支付处理的细节移出课堂。Hm-也许我用了一个不好的例子。我考虑的情况是,需要根据不同的类型做一些事情。让我改变一下问题中的例子