2009-04-09 67 views
0

我有一个系统,我一直在摔跤一段时间。从本质上讲,它使用了很多抽象来处理事实,即后期扩展不仅仅是预期的,而是必要的。一个需要的地方是数据访问。该系统通常处理管理封装了某些观察的对象(在观察值或一组值中)并使用它们。为此,我有以下效果:接口暴露类型A,但实现需要类型B(A的子类)

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

问题出现在这些接口的特定实现上。最终,ObservationObservationDataSource类用特定的运行时类实现。然而,UniqueKey也可能被扩展以处理数据源中观察的唯一标识值集(可能是一个id,也许是一个时间等)。所以GetObservationByUniqueKey的任何实现都会公开一个UniqueKey参数,但期望一个特定的子类。我预计UniqueKey一旦传入,就会被转换为特定类型。

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

任何想法修复它或更优雅地处理它?

+0

我喜欢beartato图标! =) – 2009-04-09 23:49:18

+0

哈哈,谢谢!我爱那个小家伙。 – 2009-04-10 00:48:17

回答

0

我不认为这是一个问题,只需通过修改你的这一个声明:

所以 GetObservationByUniqueKey的任何实施将暴露 一个唯一键的说法,而是奢望一段 具体子类如果和仅当 UniqueKey由此 ObservationDataSource生成。

如果唯一键是预期的类型不,这只是可以处理一个简单的拒绝情况下两种方法之一:

(1)通过在ObservationDataSource接口暴露UniqueKeyType属性,调用者GetObservationByUniqueKey可以事先检查UniqueKey的实例类型。 (2)它成为每个GetObservationByUniqueKey实现者处理UniqueKey不是由其生成的情况的合约责任。 (这对我来说似乎是完全合理的)

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

0

我不知道这是否是你想要的,但在我看来,你可以尝试使用泛型这样做:

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

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

现在接口强烈唯一键的那个特定的子类中键入您的类需要。

0

你说

所以GetObservationByUniqueKey的任何实施将暴露出唯一键的说法,

Howerver,这是不正确。它不会暴露争论 - 它会收到一个。正如你所说,调用者可能会传递任意唯一的密钥,并且没有任何问题。

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

OTOH,如果主叫方是自由选择的唯一ID,数据源应该返回一个空观察到被调用者填补,那么你有两种选择:

  1. 不要使用接口在第一位。显然,你不能用另一个实现替换一个实现,并且调用者必须知道他们使用了什么实现。
  2. 或者,确保所有实现都支持各种唯一键。
相关问题