Practice of requesting dependency in calling when programming interfaces?
When creating an interface having methods that are expected to be called in a specific order, is such dependency good practice, or should more patterns and practices be applied to "fix" it or make the situation better?
It's important users of some interfaces call methods in a specific order.
There are likely many various examples. This is the one that came to mind first:
A data source interface of which the author envisions the init method to always be called first by any caller (i.e to connect to the data source or look up preliminary meta info, etc), before any other of the operation methods are called.
interface DataAccess {
// Note to callers: this init must be called first and only once.
void Ini开发者_Go百科tSelf();
// operation: get the record having the given id
T Op_GetDataValue<T>(int id);
// operation: get a cound
int Op_GetCountOfData();
// operation: persist something to the data store
void Op_Persist(object o);
//etc.
}
However the caller may choose not to call the initialization method first.
In general I'm wondering if there are better ways for this situation.
You could have the other methods throw an exception if the object is uninitialized, or you could go for a more strict API. It would be more complicated to implement, but for example, InitSelf() could return an interface containing the data operations:
interface DataAccess {
DataOperations InitSelf();
}
interface DataOperations {
T Op_GetDataValue<T>(int id);
...
}
This would sort of require the consumer to initialize before performing operations, though there would be ways to circumvent that.
I'm a little confused. Implementors are not necessarily callers or users of the interface. In your example, implementors can assume that InitSelf is called before anything else, but aren't responsible for making that happen.
I think naming something InitXXX is a good indication that that is the case.
For more odd dependencies (not Init, which is very common), it would probably be better to not have the dependency.
Sometimes, it's not possible, and if you decide that it's not overkill to try to fix it, then a common thing is to separate into multiple interfaces that you get access to as you call early ones.
A common example is a database interface. You call connect, it returns a connection. You call createStatement on the connection, it returns a statement. You call setParam on the statement, you call runStatement on the statement, then you get a result, etc.
Any initialization should be done in the constructor. Clients of the DataAccess
interface should not have to worry about the construction details.
精彩评论