开发者

Is the StaticFactory in codecampserver a well known pattern?

开发者 https://www.devze.com 2022-12-26 07:23 出处:网络
UPDATE: this is a duplicate of Is the StaticFactory in codecampserve开发者_StackOverflow社区r a well known pattern?Edit: Please note that this answer was given before the question was completely chan

UPDATE: this is a duplicate of Is the StaticFactory in codecampserve开发者_StackOverflow社区r a well known pattern?


Edit: Please note that this answer was given before the question was completely changed over in an edit. Because of that, it now refers to things that were only present in the question as originally stated. I beg your pardon for all the "dangling pointers". :-)


Short answer:

With the code you've posted, I don't see an alternative to casting to IFoo<T>. If you don't, the compiler will give a warning (on my machine, at least).

More elaborate answer:

Does your code actually have to be that way? More specifically, do you need the cast in question in the first place?

I assume you are going to call your factory method more or less like this:

var stringFoo = FooFactory.CreateFoo<string>();

You have to provide the template parameter (string in this case) explicitly because it cannot be derived from any method argument (in this case because there aren't actually any at all). Obviously, the factory method will return an IFoo<string>.

Now, since you have to explicitly specify the type at run-time, you could just as well write:

var stringFoo = StringFoo.Create();

and therefore have a factory method inside StringFoo, like this, that unconditionally does the obvious:

public class StringFoo : IFoo<string>
{
    ...

    public static StringFoo Create()  // or alternatively, return an IFoo<string>
    {
        return new StringFoo();
    }
}

By applying this pattern to other IFoo<T> implementations too, this will save you the if chain or switch block inside FooFactory.CreateFoo<T>, make your code easier, and get rid of the necessity to cast (which you are concerned about).

Don't get me wrong, I'm aware that factory methods supporting more than one object type are useful in some cases; but it seems in your case it causes more trouble than it's worth.


P.S.: You might find one aspect of some IoC containers interesting. They usually need to be configured, and this encompasses a process where you register concrete types (i.e. implementation classes) for abstract interfaces; for example (here using Autofac):

var builder = new ContainerBuilder();
builder.RegisterType<StringFoo>().As<IFoo<string>>();

Then later, you can request an object instance of an abstract type:

using (var container = builder.Build())
{
    var stringFoo = container.Resolve<IFoo<string>>();
    ...
}

The Resolve method is the interesting part. You provide it with an abstract type, and using the registered types, it will return a concrete object of type StringFoo. Look into it, if it doesn't sound like overkill to you! :-)


Can you describe the problem you are solving with this mechanism? There is most likely a clearer way to approach it.

Edit

And yes, the code smells. You have left room open for any type, except you then constrain it back to a single type, and generate a run-time exception. Why have a type parameter in that case?


You could try something like this...

public static class FooFactory
{
    private static readonly Dictionary<Type, Type> FooTypesLookup;

    static FooFactory()
    {
        FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes()
                          let fooInterface =
                            type.GetInterfaces().FirstOrDefault(
                                x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>))
                          where fooInterface != null
                          let firstTypeArgument = fooInterface.GetGenericArguments().First()
                          select new { Type = type, TypeArgument = firstTypeArgument })
            .ToDictionary(x => x.TypeArgument, x => x.Type);
    }

    public static IFoo<T> CreateFoo<T>()
    {
        var genericArgumentType = typeof(T);
        Type closedFooType;
        return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType)
                ? (IFoo<T>) Activator.CreateInstance(closedFooType)
                : null;
    }
}

Or better yet, introduce your favorite IoC container (Windsor, structure map, etc) and register all types that implement IFoo in there and then resolve them when needed in place of the Activator.CreateInstance call.

0

精彩评论

暂无评论...
验证码 换一张
取 消