0

我有一个我一直在努力的系统。本质上,它使用大量抽象来处理以后的扩展不仅是预期的,而且是必要的。需要这样做的一个地方是数据访问。该系统通常处理封装一些观察(在观察值或一组值的意义上)并使用它们的管理对象。为此,我有一些大意:

public interface Observation 
{
    /** UniqueKey is used to access/identify an observation */
    UniqueKey Key
    {
        get;
    }
}

public interface ObservationDataSource
{
    /** 
      * Retrieves an Observation from the actual data source.
      * performs any necessary operations to encapsulate values in object
      */
    Observation GetObservationByUniqueKey(UniqueKey key);
}

这些接口的特定实现会出现问题。最终,ObservationandObservationDataSource类是用特定的运行时类实现的。但是,UniqueKey也可以扩展以处理用于数据源中观察的任何唯一标识值集(可能是 id,可能是时间等)。所以任何实现GetObservationByUniqueKey都会暴露一个UniqueKey参数,但需要一个特定的子类。我希望在UniqueKey传入后将其转换为特定类型。

这似乎是一个糟糕的设计选择,因为实现对参数要求撒谎——但我看不到另一种方法。我希望其他人使用这些接口,所以我不能说我会记住这个约定。

有什么想法可以修复它或更优雅地处理它吗?

4

3 回答 3

0

你说

所以 GetObservationByUniqueKey 的任何实现都会暴露一个 UniqueKey 参数,

然而,这是不正确的。它不会暴露参数 - 它会收到一个。正如您所说,调用者可能会传递任意唯一键,这没有任何问题。

对于特定的数据源,只有特定的唯一键才会有相关的观察 - 而不仅仅是特定的 wrt。类型,但也是具体的。为实际值。如果该值没有关联的观察,则返回 null (我想)。如果 uniqueid 的类型不正确,请执行相同的操作 - 如果有人在预期 ID 的时间过去了,则在该数据源中没有与该键关联的观察。

OTOH,如果调用者可以自由选择唯一的 id,并且数据源应该返回一个空的观察值以由调用者填充,那么您有两种选择:

  1. 首先不要使用接口。显然,您不能用一种实现替代另一种,调用者必须知道他们使用的是什么实现。
  2. 或者,确保所有实现都支持各种唯一键。
于 2009-04-10T15:09:16.420 回答
0

我不确定这是否是您想要的,但在我看来,您可以尝试使用泛型:

public interface Observation<T> where T : UniqueKey
{
    T Key { get; }
}

public interface ObservationDataSource<T> where T : UniqueKey
{
    Observation<T> GetObservationByUniqueKey(T key);
}

现在,该接口使用您的类所需的 UniqueKey 的特定子类进行强类型化。

于 2009-04-09T23:45:28.933 回答
0

我不认为这是一个问题,只需修改您的以下声明:

因此,GetObservationByUniqueKey 的任何实现都将公开一个 UniqueKey 参数,但当且仅当该 UniqueKey 是由此 ObservationDataSource 生成时才需要一个特定的子类。

如果 UniqueKey 不是预期的类型,那只是一个微不足道的拒绝案例,可以通过以下两种方式之一处理:

(1) 通过在 ObservationDataSource 接口中暴露 UniqueKeyType 属性,GetObservationByUniqueKey 的调用者可以先验地检查 UniqueKey 的实例类型。

(2) 每个 GetObservationByUniqueKey 实现者的合同责任是处理其未生成 UniqueKey 的情况。(这对我来说似乎完全合理)

但是,您的整个问题都引出了一个问题-当您已经定义了查找函数来获取数据对象时,为什么要首先允许 UniqueKey 是多态的?

于 2009-04-10T00:29:32.307 回答