如何为不同的子类实现接口的多个实例?

How to implement multiple instances of interface for different subclasses?

我有一个很大的 class,用于保存两组不同的相同 class 的不同信息。例如,假设收据可以是客户收据或内部收据。所有这些信息都在一个巨大的 class 中,因为这就是数据库的结构,但我想将 class 分开,这样我就会有一张包含所有共享信息的收据 class 、客户收据 class 和内部收据 class。他们可以共享一个接口,但实现会有所不同,这让我很困惑。

是否应该实现两个单独的接口?所以我会有 ICustomerReceipt 和 IInternalReceipt?我认为应该有一个接口,比如 Get() 和 Save() 方法,如果是客户收据或内部收据,我会根据实现获取特定于 class 的信息。我有点迷路了。

public class Receipt { 
    public int ID { get; set; } 
    public int ReceiptNumber { get; set; }
    public List<string> Items { get; set; }
}

public class CustomerReceipt : Receipt { 
    public string CustomerNumber { get; set; } 
    public string CustomerEmail { get; set; }
    public string CustomerOption { get; set; }
}

public class InternalReceipt : Receipt {
    public string InternalNumber { get; set; }
    public string InternalEmail { get; set; }
    public string InternalOption { get; set; }
}

public interface IReceiptRepository { 
    public Receipt Get(int id);
    public Receipt Add(Receipt receipt);
}

public CustomerReceiptRepository : IReceiptRepository {
    public CustomerReceipt Get(int id) {
        // get information about customer receipts here
    }
}

public InternalReceiptRepository: IReceiptRepository {
    public InternalReceipt Get(int id) {
        // get information about internal receipts here
    }
}

基本上我只是想 return 将正确的收据发送到我的控制器中只有通用 'ReceiptNumber' 或 'ReceiptEmail' 的视图模型。我知道这不是最好的例子,但这是我能想到的唯一例子。

不要因为试图强制两个相似的事物共享一个抽象(基础 class 或接口)而被绊倒。所以,我会推荐你​​的建议:创建两个单独的接口。

记住,多态性的意义在于,如果您只是在寻找实例,那么您不必知道实例的具体 (derived/implemented) 类型基础 type/interface 的一个实例。而已。如果你不需要那个,那么绕过圈子迫使两个相似的 classes 共享一个基地是不值得的。

public interface IReceiptRepository { 
    public Receipt Get(int id);
    public Receipt Add(Receipt receipt);
}

public CustomerReceiptRepository : IReceiptRepository {
    public Receipt Get(int id) {
        // get information about customer receipts here
        return new CustomerReceipt();
    }
}

public InternalReceiptRepository: IReceiptRepository {
    public Receipt Get(int id) {
        // get information about internal receipts here
        return new InternalReceipt();
    }
}

继承可以用不同的方式在数据库上表示,并且有一些策略取决于您使用的 ORM。 归根结底,使用其中一种策略,您可以将您的存储库建立在基础class之上,让ORM充当代理来解析您需要的实例,或者尝试在存储库级别根据鉴别器字段重新创建您需要的实例

Receipt
    ID 
    ReceiptNumber 
    CustomerNumber 
    CustomerEmail 
    CustomerOption 
    InternalNumber 
    InternalEmail 
    InternalOption 
    DISCRIMINATOR_FIELD

(大多数 ORM 都会为您完成此翻译),但为了让您了解这个想法,您可以只保留一个存储库以将所有 classes 视为收据并保持您的层次结构它。

public 接口 IReceiptRepository { public收据获取(int id); public收据添加(收据收据); }

public CustomerReceiptRepository : IReceiptRepository {
    public Receipt Get(int id) {
            var rec = DbContext.Table.Receipt.FirstOrDefault(r => r.id = id);
            if(rec.DiscriminatorField == 1) //CustomerReceipt
            {
                return new CustomerReceipt
                {
                     ID = ...
                     ReceiptNumber = ...
                     CustomerNumber = ...
                     CustomerEmail = ...
                     CustomerOption = ...
                 }
              }
              //all other cases are InternalReceipts
              return new InternalReceipt
              {
                   ID = ...
                   ReceiptNumber = ...
                   InternalNumber  = ...
                   InternalEmail = ... 
                   InternalOption = ...
              }
    }
}

Add 方法也是如此,只需填写该对象所需的字段即可。这种组合将一切都基于鉴别器领域。 我并不是在建议您以这种方式实施您的解决方案,但这样一来,您仍然可以在 ViewModel 上获得通用收据。我的建议是您阅读更多关于您正在使用的 ORM 以及如何在那里表示继承的信息(也许您首先使用数据库而不是代码,您将需要手动处理这些事情,因为数据库不是以这种方式设计的你需要采取与我建议的类似的方法。但是如果你有机会创建你的 POCO classes 并创建数据库,那么绝对值得看看它们是如何实现继承的。

我在这里附上 link 这个问题是如何在 EntityFramework 6

上解决的

Inheritance Strategy in Entity Framework 6

希望对您有所帮助