I have a system which I've been wrestling with for a while. Essentially, it uses a lot of abstraction to deal with the fact that later extension is not just expected, but necessary. One place this is required is data access. The system generally deals with managing objects encapsulating some observation (in the sense of an observed value or set of values) and using them. To this end, I have something to the effect of:
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);
}
The problem arises for specific implementations of these interfaces. Eventually, the Observation
and ObservationDataSource
class are implemented with specific runtime classes. However, UniqueKey
may also be extended to deal with whatever the uniquely identifying set of values are for an observation in the data source (maybe an id, maybe a time, etc). So any implementation of GetObservationByUniqueKey
will expose a UniqueKey
argument, but expect a specific subclass. I expect the UniqueKey
to be casted to a specific type once passed in.
This seems like a poor design choice, since the implementation is lying about the argument requirements -- but I can't see another way of doing this. I expect other people to be using these interfaces, so I can't just say that I'll remember this convention.
Any ideas to fix it or handle it more elegantly?