开发者

Using Funcs instead of instances in frameworks

When looking at the source code of a couple of projects I found a pattern I can not quite understand. For instance in FubuMVC and Common Service Locator a开发者_如何学C Func is used when a static provider is changed. Can anyone explain what the benefit is of using:

private static Func<IServiceLocator> currentProvider;
public static IServiceLocator Current
{
   get { return currentProvider(); }
}

public static void SetLocatorProvider(Func<IServiceLocator> newProvider)
{
   currentProvider = newProvider;
}

instead of:

private static IServiceLocator current;
public static IServiceLocator Current
{
   get { return current; }
}

public static void SetLocator(IServiceLocator newInstance)
{
   current = newInstance;
}


The major advantage of the first model over the second is what's called "lazy initialization". In the second example, as soon as SetLocator is called, you must have an IServiceLocator instance loaded in memory and ready to go. If such instances are expensive to create, and/or created along with a bunch of other objects at once (like on app startup), it's a good idea to try to delay actual creation of the object to reduce noticeable delays to the user. Also, if the dependency may not be used by the dependent class (say it's only needed for certain operations, and the class can do other things that don't require the dependency), it would be a waste to instantiate one.

The solution is to provide a "factory method" instead of an actual instance. When the instance is actually needed, the factory method is called, and the instance is created at the last possible moment before it's used. This reduces front-end loading times and avoids creating unneeded dependencies.


Good answer by @KeithS. Another thing to note here is what happens under the covers of the initialization of certain instances. Keeping a reference to intentionally volatile objects can be tricky.

FubuMVC, for instance, spins up a nested StructureMap container per HTTP request which scopes all service location to that specific request. If you have classes running within that pipeline that have been built up, you'll want to use the contextual injection provided to you via THAT instance of IServiceLocator.


Theres a lot more flexibility to the implementer of newProvider. They can lazy load, async load (and and then if it's not loaded by the time the func is called it can have code to wait), they can allow it change based on runtime parameters etc.


A func allows several things

  1. The locator creation can be delayed until it is needed. It is therefore lazy.
  2. The provider object does not contain any state. It is not its responsiblity to shut down the locator does anything with it except to return the current locator when needed.
  3. When the locator is reconfigured at run time or it decides that a different instance is needed it can control the lifetime of the locator as long as the calling code does not store a reference to locator.
  4. Since the locator is returned by a method it has more flexibility e.g. to create a thread local locator so it can create many objects in each thread without the need to coordinate object creation in one global object which could become a bottleneck when many threads are involved.

I am sure the designers did could give you more points than I did why it can be a good idea to abstract away "simple" things like to return an instance of a service locator.

Yours, Alois Kraus

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜