2012-11-05 106 views
0

如何声明用于通用类型实例的变量?声明通用类型的实例

在控制器中,我需要创建依赖付款类型的实例,并且每个类都有不同类型的参数。这就是我使用泛型的原因。 但我不知道我需要设置什么类型来为每个支付类别定义变量。

模型参数

public class PaymentModel 
{ 
    public string orderNo { get; set;} 
} 

public class CCPaymentModel : PaymentModel 
{ 
    public string CCNo {get; set;} 
    public string expDate {get; set;} 
} 

public class PaypalPaymentModel : PaymentModel 
{ 
    public string paypalID {get; set;} 
} 

public class GooglePaymentModel : PaymentModel 
{ 
    public string googleID {get; set;} 
} 

接口类,我使用泛型类型的参数,因为各种付款方式需要不同类型的参数。

public interface IPayment<T> where T : PaymentModel 
{ 
    void makePayment(string orderNo); 
    void makeRefund(T refundInfo); 
} 

模型,

public class SagePayment 
    : IPayment<CreditCardPaymentInfo> 
{ 
    public void MakePayment(CreditCardPaymentInfo creditCardPaymentInfo) { 
     // make payment 
    } 

    public void MakeRefund(CreditCardPaymentInfo creditCardPaymentInfo) { 
     // make refund 
    } 
} 

public class GooglePayment 
    : IPayment<GooglePaymentModel> 
{ 
    public void MakePayment(GooglePaymentModel paymentInfo) { 
     // make payment 
    } 

    public void MakeRefund(GooglePaymentModel paymentInfo) { 
     // make refund 
    } 
} 

public class PaypalPayment 
    : IPayment<PayPalPaymentModel> 
{ 
    public void MakePayment(PayPalPaymentModel paymentInfo) { 
     // make payment 
    } 

    public void MakeRefund(PayPalPaymentModel paymentInfo) { 
     // make refund 
    } 
} 

控制器(创建实例)

public void Charge(string paytype,orderNo){ 

    IPayment<???> paymentProcess; // //Error 1 Using the generic type 'com.WebUI.Models.IPayment<T>' requires 1 type arguments 
    Object payinfo; // 

    if (Regex.IsMatch(paytype, "^Credit Card")) 
    { 
     paymentProcess = new SagePayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); // it return CCPaymentModel type object 
    } 
    else if (Regex.IsMatch(paytype, "^PayPal")) 
    { 
     paymentProcess = new PayPalPayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); // it return PaypalPaymentModel type object 
    } 
    else if (Regex.IsMatch(paytype, "^Google")) 
    { 
     paymentProcess = new GooglePayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); // it return GooglePaymentModel type object 
    } 

    paymentProcess.MakePayment(payinfo); 
} 

为了避免错误,我会这样,

public void Charge(string paytype,orderNo){ 

    if (Regex.IsMatch(paytype, "^Credit Card")) 
    { 
     IPayment<CCPaymentModel> paymentProcess = new SagePayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); 
     paymentProcess.MakePayment(payinfo); 
    } 
    else if (Regex.IsMatch(paytype, "^PayPal")) 
    { 
     IPayment<PaypalPaymentModel> paymentProcess = new PayPalPayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); 
     paymentProcess.MakePayment(payinfo); 
    } 
    else if (Regex.IsMatch(paytype, "^Google")) 
    { 
     IPayment<GooglePaymentModel> paymentProcess = new GooglePayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); 
     paymentProcess.MakePayment(payinfo); 
    } 
} 

public void Refund(string paytype,orderNo){ 

    IPayment<???> paymentProcess; // //Error 1 Using the generic type 'com.WebUI.Models.IPayment<T>' requires 1 type arguments 
    Object payinfo; // 

    if (Regex.IsMatch(paytype, "^Credit Card")) 
    { 
     paymentProcess = new SagePayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); // it return CCPaymentModel type object 
    } 
    else if (Regex.IsMatch(paytype, "^PayPal")) 
    { 
     paymentProcess = new PayPalPayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); // it return PaypalPaymentModel type object 
    } 
    else if (Regex.IsMatch(paytype, "^Google")) 
    { 
     paymentProcess = new GooglePayment(); 
     payinfo = getPaymentInfo(paytype, orderNo); // it return GooglePaymentModel type object 
    } 

    paymentProcess.MakeRefund(payinfo); 
} 

但我知道这是不对的办法。

有人知道,请指教我。

+0

@millimoose如何重构设计,你能解释一些更多细节吗?我现在正在学习OOP,所以我想知道可以在真实项目中使用的正确方法。 –

+0

一般来说,当你在类集之间有这种1:1对应关系时,这是一种设计气味,**和**它暴露给这些类的客户端。这是控制器类应该隐藏的内容。 – millimoose

回答

1

你可以做Charge()getPaymentInfo()是通用针对的PaymentModel类型:

void Charge<TPaymentModel>(...) where TPaymentModel : PaymentModel { 
    IPayment<TPaymentModel> payment = GetPayment<TPaymentModel>(); 
    // ... 
    payment.MakePayment(getPaymentInfo<TPaymentModel>(...)); 
} 

IPayment<TPaymentModel> GetPayment<TPaymentModel>() where TPaymentModel : IPaymentModel 
{ 
    // Create payment of appropriate type based on typeof(TPaymentModel) 
} 

TPaymentModel GetPaymentInfo(...) where TPaymentModel : PaymentModel 
{ 
    // Create payment model of appropriate type based on typeof(TPaymentModel) 
} 

这还是有点难看,要解决这个你可能会引入一些新的类隐藏的对应关系从类型的接口,使设计更加完善:

/// Abstracts over different ways of making payments 
interface IPaymentMaker 
{ 
    void MakePayment(string payType, long orderNo); 
    // MakeRefund etc. 
} 

/// Refactor code common to all payment types here, and handle the association 
/// between payment and payment model. 
class PaymentMakerBase<TPaymentModel> : IPaymentMaker 
    where TPaymentModel : IPaymentModel 
{ 
    void MakePayment(string payType, long orderNo) 
    { 
     NewPayment().MakePayment(NewPaymentModel(payType, orderNo)); 
    } 

    abstract IPayment<TPaymentModel> NewPayment(); 
    abstract TPaymentModel NewPaymentModel(string payType, long orderNo); 
} 

/// Handle only the differences between payment types that can't be put inside their 
/// implementations 
class PaypalPaymentMaker : PaymentMakerBase<PaypalPayment> 
{ 
    IPayment<PaypalPayment> NewPayment() { ... } 
    PaypalPayment NewPaymentModel(...) { ... } 
} 

static class PaymentMakerFactory 
{ 
    /// The only "not type safe" part, handles parsing the payType string and 
    /// resolving it to the correct `PaymentMaker` 
    public IPaymentMaker GetPaymentMaker(string payType) 
    { 
     if (Regex.IsMatch(payType, ...)) 
     { 
      // return appropriate payment maker for the payType 
     } 
     else if (...) 
     { 
      // ... 
     } 
    } 
} 

然后,控制器代码仅是这样的:

PaymentMakerFactory.GetPaymentMaker(payType).MakePayment(payType, orderNo); 

显然,上述设计可以通过删除冗余(payType可能是不需要的,我到处都包括它),使其更加“objecty”(而不是周围传递相同的参数列表),或者更方便(PaymentMakerFactory改善可能可能会更改为外观,它会创建正确的付款方,然后立即致电MakePayment)。

+0

谢谢你的回答!我现在正在阅读你的答案10次,但是仍然很难理解,我会再读100遍。顺便说一句,这是为了什么? NewPayment()。MakePayment(NewPaymentModel(payType,orderNo)); –

+0

@Expert我建议把代码放入VS并单击它。它在功能上是你的代码,只是分成多个类。在我使用'...'的地方,代码与您已有的代码相同(并且未在您的问题中列出)。基本上,您现在在控制器中的代码主要位于'PaymentMakerBase'中。除了每种支付类型不同的部分外,这些部分都在'PaymentMakerBase'的子类中。 'NewPayment()。MakePayment(...)'对应于'if(Regex.IsMatch(...))'子句的内容。 – millimoose

+0

我明白了,谢谢! –

3

鉴于您的MakePayment方法确实需要而不是需要T,因此在单独的界面中声明它可能是最简单的。你既可以使通用接口扩展非泛型之一:

// Capitalization fixed to comply with conventions 
public interface IPayment 
{ 
    void MakePayment(string orderNo); 
} 

public interface IRefundPayment<T> : IPayment where T : PaymentModel 
{ 
    void MakeRefund(T refundInfo); 
} 

或只是有他们作为单独的接口:

public interface IPaymentHandler 
{ 
    void MakePayment(string orderNo); 
} 

public interface IRefundHandler<T> where T : PaymentModel 
{ 
    void MakeRefund(T refundInfo); 
} 

无论哪种方式,你那么只需要在非泛型接口的Charge方法。

+0

如果移动到makeRefund的情况下,那么它面临同样的问题。 –