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);
}

しかし、私はそれが正しい方法ではないことを知っています。

分かる方、アドバイスお願いします。

4

2 に答える 2

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

于 2012-11-05T19:51:43.343 に答える
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 は、私が含めたすべての場所でおそらく必要ありません)。より「客観的」に (同一の引数リストを渡す代わりに)、またはより便利にします (おそらくファサードPaymentMakerFactoryに変更できます)。適切な支払いメーカーを作成し、すぐに呼び出します)。MakePayment

于 2012-11-05T20:51:39.920 に答える