类设计 - 接口还是抽象类?

时间:2014-03-27 07:11:28

标签: c# class-design

我的业务情景如下:

我们可以使用多种支付系统(PS1,PS2,PS3 ......)进行付款。常见的功能是 - ProcessPayment。付款基于数据库中的数据。

我可以使用哪种设计?

1)使用ProcessPayment方法和PaymentSystemBase基类创建IPaymentSystem接口,该基类适用于数据库内容,如连接,检索数据等。创建特定的类PS1,PS2,PS3 ......实现IPaymentSystem接口,并从PaymentSystemBase基类派生,以便使用常见的数据库内容。

2)创建包含所有ProcessPayment方法和数据库内容的抽象基类。

3)其他东西。

interface IPaymentSystem
{
    void ProcessPayment();
}

public class PaymentSystemBase
{
    public PaymentSystemBase()
    {
        CheckInputParameters();
        CreateDatabaseConnection();
    }

    protected void CheckInputParameters() {}
    protected void CreateDatabaseConnection() {}
}

public class PS1 : PaymentSystemBase, IPaymentSystem
{
    public void ProcessPayment()
    {
        Console.WriteLine("Process PS1...");
    }
}

public class PS2 : PaymentSystemBase, IPaymentSystem
{
    public void ProcessPayment()
    {
        Console.WriteLine("Process PS2...");
    }
}

4 个答案:

答案 0 :(得分:2)

从您的代码中我假设,为了付款,我必须: - 验证/检查参数 - 处理数据库连接 - 可能更多

在我看来,这些行动应该由两个不同的对象完成。 PaymentSystem应该将它们用作协作者。没有抽象类。

这里的经验法则是“赞成合成而不是继承”:http://www.hautelooktech.com/2013/02/05/design-principle-favor-composition-over-inheritance/

为了能够创建不同的支付系统,您可以从PaymentSystem的每个协作者中提取一个界面,并通过属性注入或更好的构造函数注入来切换它们(也就是组成一个新的支付系统)。

http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/

总而言之,您的PaymentSystem应该是非常简单的协作者的“协调者”。

答案 1 :(得分:0)

我会使用第一种方法,Interface,Abstract类来实现一般方法和具体类。

在我看来,抽象类绝不是接口的替代品,所以我将放弃第二种方法。

其他解决方案可能取决于您的业务,要求......

唯一可能出错的是,您的课程可能会违反单一的责任,因为它必须处理付款等事情并创建数据库连接。对我来说,数据库连接应该在另一个地方。

此致

答案 2 :(得分:0)

在这种情况下,我建议您使用Interface。只涉及一种方法。您可以为各种付款类型(PS1,PS2,PS3 ......)提供自己的实施。

如果你有一些情况,你有更多的方法和变量,这对于ProcessPayment来说是常见的,那么你可以想到抽象类,其中至少有一些方法行为不会被改变。但请记住,当您使用Abstract类时,您正在丢失类继承。

如果只涉及一种方法,那么请使用Interface。

答案 3 :(得分:0)

你宁愿创建一个抽象类来放置所有数据库的东西; 如果你想声明接口,那么抽象类应该实现它:

// Not necessary
public IPaymentable {
  void ProcessPayment();
}

// Interface should be implemented here
public abstract class PaymentSystemBase: IPaymentable {
  ...
  private IDatabaseConnection connectToDatabase() {...}
  ...
  protected void loadFromDatabase() {...}
  protected void saveToDatabase() {...} 
  ...
  protected PaymentSystemBase() {...}

  public abstract void ProcessPayment();
}

// A concrete class should only override ProcessPayment() method
public class PS1: PaymentSystemBase {
  public override void ProcessPayment() {...}
}

// A concrete class should only override ProcessPayment() method
public class PS2: PaymentSystemBase {
  public override void ProcessPayment() {...}
}