There are quite a few solutions to this.
- Have your service proxy classes implement your own interface to expose the methods, and then simply use reflection to build a type.
- Wrap both services in another class that exposes the methods and has a reference to both services, then simply provide a switching argument to determine which to use.
- Abstract the use of a service via your own interface and have classes coded against each service explicitly (see below).
Or if you want to play with dynamic and duck typing, this seemed to work:
namespace ConsoleApplication42
{
class Program
{
static void Main(string[] args)
{
Type t1 = Type.GetType("ProviderOne.AuthService");
dynamic service = Activator.CreateInstance(t1);
Console.WriteLine(service.GetUsername());
Type t2 = Type.GetType("ProviderTwo.AuthService");
service = Activator.CreateInstance(t2);
Console.WriteLine(service.GetUsername());
Console.Read();
}
}
}
namespace ProviderOne
{
public class AuthService
{
public string GetUsername()
{
return "Adam";
}
}
}
namespace ProviderTwo
{
public class AuthService
{
public string GetUsername()
{
return "Houldsworth";
}
}
}
Bear in mind they all hinge on both services having the same signature.
As for the other services in future, it really depends. I've never really encountered a need to dynamically switch from one service to another to get slightly different behaviour in achieving the same thing.
Perhaps this should be driven from your app's side? Instead of a service being chosen to suit, simply implement two versions of the class that has this changing behaviour - put a common interface on it, and decide which of your classes to use at runtime. The class itself will then be coded directly against one of the services.
interface IGetUsername
{
string GetUsername();
}
class UsernameViaProviderOne : IGetUsername
{
public string GetUsername()
{
return new ProviderOne.AuthService().GetUsername();
}
}
class UsernameViaProviderTwo : IGetUsername
{
public string GetUsername()
{
return new ProviderTwo.AuthService().GetUsername();
}
}
Then the decision is firmly in your client code and removes the need for reflection/dynamic typing:
IGetUsername usernameProvider = null;
if (UseProviderOne)
usernameProvider = new UsernameViaProviderOne();
...
To labour the point, you could always get very SOA and create yet another service that your app talks to that aggregates the other two services. Then at least your client code doesn't see the huge number of different services and talks to just one.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…