6

我不明白如何清楚地使用接口类。我阅读了很多关于接口类相关 OOP 的文章和教程,所以我知道接口是什么,但我确实了解在实际项目中使用。

例如,

我制作了 IPayment 接口类。我定义了 2 种使用所有支付类通用的方法。

public interface IPayment 
{
  void MakePayment(OrderInfo orderInfo);
  void MakeRefund (OrderInfo orderInfo);
}

我做了 3 个支付类,分别是 CreditCardPayment、PaypalPayment 和 GooglePayment。

我在每个类中定义了 2 个方法。

我在这部分感到困惑,我需要创建 OrderInfo 类,其中包含需要用于处理付款或退款的订单信息。每个班级需要不同的信息。

CreditCartPayment 类需要 Credit Card No, Expiration Date .... 但其他支付类不需要。

GooglePayment 类需要 Google 订单号,而其他类则不需要。

所以,最后 OrderInfo 类必须有许多额外的字段。而且看起来很脏...

前任)

Public class OrderInfo 
{
  /* For Common */
  string orderNo {get; set;}
  string customerNo { get; set;}
  decimal amount {get; set;}

  /* For Credit Card */
  string CCNum {get; set;}
  string expDate { get; set;}

  /* For Google */
  string googleOrderID {get; set;}
  ...

  /* For Paypal */
  ...
}

我的问题是,

在这种情况下,使用 IPayment 是否正确?或者我需要在没有接口类的情况下使用正确的参数定义每个类?

我想使用接口类的好处是以后很容易弄清楚支付类。因为接口类将显示每个支付类中定义了哪些方法。还有其他优点吗?

您对在现实世界中理解接口类有什么建议吗?

[编辑]

谢谢你的建议。

我再次编写示例代码。你能检查一下这段代码吗?

public interface IPayment 
{
  void MakePayment(OrderInfo orderInfo); // !!
  void MakeRefund (OrderInfo orderInfo); // !!
}

public class OrderInfo 
{
  protected string OrderNo {get; set;}
  protected string CustomerNo { get; set;}
  protected decimal Amount {get; set;}
}

public class CreditCardPaymentInfo : OrderInfo
{
  string CCNum {get; set;}
  string ExpDate { get; set;}
}

public class GooglePaymentInfo : OrderInfo
{
  string GoogleOrderID {get; set;}
}

public class PaypalPaymentInfo : OrderInfo
{
  string PaypalID {get; set;}
}



public void MakePayment()
{
    IPayment paymentModule;
    // Get Order Info 
    if(orderType == "Paypal"){
        paymentModule = new PaypalPayment();

        PaypalPaymentInfo orderInfo = new PaypalPaymentInfo();
        orderInfo.PaypalID = "TEST";
    }else if(orderType == "Google"){
        paymentModule = new GooglePayment();

        GooglePaymentInfo orderInfo = new GooglePaymentInfo();
        orderInfo.GoogleOrderID = "TEST";
    }else{
        paymentModule = new CreditCardPayment();

        CreditCardPaymentInfo orderInfo = new CreditCardPaymentInfo();
        orderInfo.CCNum = "1111111111111111";
        orderInfo.ExpDate = "11/11";
    }

    orderInfo.OrderNo = "123";
    orderInfo.CustomerNo = "ABC";
    orderInfo.Amount = 12.20m;

    paymentModule.MakePayment();
}

它发生错误:

错误 1 ​​'com.WebUI.Models.CreditCardPaymentInfo' 没有实现接口成员 'com.WebUI.Models.IPaymentProcess.makeRefund(WebUI.Models.RefundModel)'

我想我需要修复接口类。有人知道我应该如何解决吗?

4

6 回答 6

6

一种方法是创建OrderInfo一个基类,并使您的提供商特定的支付类型成为它的子类,如下所示:

public class OrderInfo 
{
  /* For Common - Protected members are accessible to subclasses! */
  protected string OrderNo {get; set;}
  protected string CustomerNo { get; set;}
  protected decimal Amount {get; set;}
}

public class CreditCardPaymentInfo : OrderInfo
{
  /* For Credit Card */
  string CCNum {get; set;}
  string ExpDate { get; set;}
}

public class GooglePaymentInfo : OrderInfo
{
  /* For Google */
  string GoogleOrderID {get; set;}
  ...
}

public class PaypalPaymentInfo : OrderInfo
{
  /* For Paypal */
  ...
}

然后,您可以像这样实现您的 Payment 类,并满足 IPayment 接口的要求:

public class PaypalPayment : IPayment
{
    public void MakePayment(PaypalPaymentInfo orderInfo)
    {
      ...
    }

    public void MakeRefund (PaypalPaymentInfo orderInfo)
    {
      ...
    }
}

因为PaypalPaymentInfo可以在任何OrderInfo指定的地方使用,所以这是一个有效的实现IPayment。对于信用卡和 Google 付款实施,您可以遵循相同的模式。

于 2012-11-02T19:32:36.940 回答
5

实现这一点的正确方法是为每种类型的付款创建一个类,但将它们用作一般的IPayment. 所以你会有:

public class CreditPayment : IPayment

public class GooglePayment : IPayment

public class PaypalPayment : IPayment

然后使用付款:

public class PaymentUser
{
   private IPayment _payment;

   public PaymentUser(//args)
   {
      //Which payment to be used would be based on args. Using a factory here is common
      _payment = new CreditPayment(//args);
   }
}

现在您已经IPayment为您创建了一个,并且您不关心它是什么类型,除了知道它履行您的合同!

所以在某个地方你可以说

public void MakePayment(OrderInfo order)
{
   _payment.MakePayment(order);
}

而且您甚至不知道IPayment您使用的是哪种类型。这增加了可扩展性,因为您不关心执行该方法的类型,只要它遵循IPayment接口即可。

于 2012-11-02T19:24:34.180 回答
1

让我试着用简单的例子来解释它。

想一个简单的方法(例如)说int rectanglePerimeter(int x, int y)。该方法只取两个数字,将它们相乘并返回结果。现在您可以通过两种方式实现它:

第一:使用乘法

    return x*y;

第二:使用加法

    int res = 0;
    for(int i=0; i< length; i++){
      res+= width;
    }
    return res;

现在,如果您想保持此方法的使用者代码独立于实现,您可以简单地定义一个Interface具有方法签名的int rectanglePerimeter(int x, int y). 这可能由不同的实现主体以不同的方式实现,但都必须遵守方法定义,并且您的使用者代码模式不会根据实现而改变。

现在让我们举一个更实际的Database queries execution使用Connection接口的例子。由于有多个数据库提供程序,它们都有不同的实现(数据库驱动程序)来支持与数据库的连接,但它们都提供与Connection接口中定义的相同的方法支持,例如commit(), createStatement(), rollback()& close()

这使得使用独立于实现。正如你现在可以想象的那样,Interface在消费者和服务提供者之间扮演着服务契约的角色。消费者和服务提供者可能都是您自己的类,或者它可能来自两个不同的组/组织。

于 2012-11-02T19:34:05.673 回答
1

我会给你一些关于接口如何工作的例子。无论如何,您有很多方面可以使用 界面

接口继承(又名类型继承):这也称为子类型化。接口提供了一种机制来指定其他不相关的类之间的关系,通常通过指定每个实现类必须包含的一组公共方法。接口继承将程序的设计理念提升为接口而不是实现。这也减少了系统之间的耦合或实现依赖。在 Java 中,您可以实现任意数量的接口。这比实现继承更灵活,因为它不会将您锁定在使子类难以维护的特定实现中。所以应该注意不要通过修改接口来破坏实现类。

例子:

假设我们有一个名为Person.

包含以下Person字段:年龄、名字、姓氏、ID、军人 ID(例如兵役)、工作地点等。现在,您想向工作、军队、脸书等多个机构提供人员信息。您的工作不想在 facebook 上听到有关您的军人身份或昵称的所有信息。因此我们创建了几个接口:MilitaryItf,WorkItf ,WebPersonItf . InWebPersonItf you define methodsget/set Nick name, First Name, gmail and so on. InMilitaryItf you provideget/set` 用于年龄、健康、军人ID、服役开始/结束日期……最后每个机构只使用从“Person”派生的感兴趣的方法。

于 2012-11-02T19:39:00.703 回答
1

接口用于能够使用不从同一基类继承的类。你为这三个课程所做的看起来很合理。但也可以创建一个“基类”,用于继承接口中的函数。

您的问题OrderInfo不在于界面,而更多在于您基本上需要一种不同类型的对象。或多或少,您的界面不适合您的CreditCartPayment课程。

一种出路是创建一个从该类继承的OrderInfo类,CredidCardOrderInfo并在该类中使用它CreditCardPayment。您可以使用CreditCardOrderInfo该类的任何实例,就好像它是一个OrderInfo实例一样。然后你添加一行

CreditCardOrderInfo info = orderInfo as CreditCardOrderInfo;
if (info == null) throw new ArgumentException("orderInfo has no credit card order info");

它把东西放在一起......但仍然很脏。

于 2012-11-02T19:41:26.163 回答
1

接口的目的是允许持有对实现它的对象的引用的实体使用该对象,而不必知道它可能碰巧是许多可能的实现中的哪一个。因此,接口通常应该只定义可能对所有实现它的类有用的方法。

根据您的场景,听起来需要的不是支付处理类的接口,而是接口IOrderWithPayment,用于预期封装某种形式的订单信息的对象和可以接受它的支付处理器对象(即特定种类的订单信息)。然后,该接口将具有将订单信息提供给支付处理器的方法MakePaymentMakeRefund持有 an 的对象IOrderWithPayment不必担心其中封装了哪种类型的订单信息或支付处理器,因为实现的每个类IOrderWithPayment都会封装相互兼容的订单信息和支付处理器类型。

请注意,可以定义一个通用类来处理订单信息和支付处理器对象的所有兼容组合,前提是这些对象包含关于它们可以接受什么的适当声明,但这需要使用一些相当高级的概念. 目前,定义封装兼容的对象组合的不同类型可能更容易。

于 2012-11-02T19:57:27.387 回答