How to indicate which implementation of an interface to return, based on some flag/argument?
In a distributed application that has multiple databases that support it, we're looking for better ways to handle the creation of the database connections. For example, suppose your system has three database behind it:
- Business Data (orders, products, categories, etc)
- Metadata (data about the structure of the business data)
- User Data (user preferences, saved artifacts, etc)
The details of the data aren't important... it's simply three databases. Throughout your app, you want to get connections to these three and return an IDbConnection implementation. The implementation used for User Data may differ slightly than the one used for Business Data. and so on. Connection strings for each are in a config file.
So we've looked at a couple of approaches, including:
Factory with Multiple Methods
class ConnectionFactory {
public static IDbConnection CreateBusinessDataConnection()
{
//
}
public static IDbConnection CreateMetadataConnection()
{
//
}
public static IDbConnection CreateUserDataConnection()
{
//
}
}
... in this example, though, we might just as well return a specific implementation rather than the IDbConnection reference. The downside being that we couldn't change the type of connection used without changing the consumer code later.
Factory with Single Method
In this case, we use a single method and 开发者_StackOverflow中文版pass in some value (likely an enum) to indicate what connection type we want:
enum DbConnectionType { BusinessData, Metadata, UserData }
class ConnectionFactory {
public static IDbConnection CreateDataConnection(DbConnectionType connType)
{
// look at connType and probably use a switch statement to create
// the connection for that type.
}
}
These both have upsides and downsides... to add to the mix, we've recently started using the Unity IoC container from Microsoft in the project. It seems like this might be valuable here, but it's early in our understanding. On the surface, it doesn't look like it helps us because we're not registering a concrete type.
container.Register(IDbConnection, [ which of the three implementations ? ]);
Instead, it's more like we're saying "When I request an IDbContainer and I also provide you with this enum value, please return THIS implementation of IdbConnection." We've yet to find a way to do that in Unity (but again, it's still new to us and we're working through samples).
Thoughts?
The second variant looks best to me (although the first is barely different). The advantage of this is that the only code that has to know or think about which database to connect to is the code that calls the ConnectionFactory
--everything else can just use the generic IDBConnection
interface.
Assuming that a particular instance of your application will be using the same type of connection for each of the database types (i.e. one provider per application), you can implement classes for each of the different connection providers and make the ConnectionFactory an interface.
Then register each of the connection factory implementations as a Named type in Unity.
When the application goes to resolve the connection factory, you can have the provider defined as a setting in the configuration file, that way no recoding is necessary if they later change providers.
Put the methods of the first design into the body of the method of the second design. Then, you implement an instance of the Factory design pattern.
精彩评论