SPRNET-1514 adding DelegatingFactoryObject<T> and related tests

This commit is contained in:
Steve Bohlen
2012-07-18 10:29:42 -04:00
parent 7318d07d48
commit 19fd1876d8
6 changed files with 175 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
#region License
/*
* Copyright © 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
namespace Spring.Objects.Factory.Support
{
/// <summary>
/// Convenience implementation of the <see cref="IFactoryObject"/> interface that
/// delegates to an arbitrary object + method to perform the object construction.
/// </summary>
/// <remarks>
/// <para>
/// Because this <see cref="IFactoryObject"/> implementation requires a delegate
/// passed to its ctor, its only possible to configure this object and register
/// it with the <see cref="IObjectFactory"/> via code rather than via XML.
/// </para>
/// </remarks>
/// <typeparam name="T"></typeparam>
public class DelegatingFactoryObject<T> : IFactoryObject
{
private readonly bool _isSingleton;
private readonly Func<T> _builderDelegate;
/// <summary>
/// Initializes a new instance of the <see cref="DelegatingFactoryObject&lt;T&gt;"/> class.
/// </summary>
/// <param name="builderDelegate">The builder delegate.</param>
/// <param name="isSingleton">if set to <c>true</c> [is singleton].</param>
public DelegatingFactoryObject(Func<T> builderDelegate, bool isSingleton)
{
_builderDelegate = builderDelegate;
_isSingleton = isSingleton;
}
/// <summary>
/// Return an instance (possibly shared or independent) of the object
/// managed by this factory.
/// </summary>
/// <remarks>
/// <note type="caution">If this method is being called in the context of an enclosing IoC container and
/// returns <see langword="null"/>, the IoC container will consider this factory
/// object as not being fully initialized and throw a corresponding (and most
/// probably fatal) exception.
/// </note>
/// </remarks>
/// <returns>
/// An instance (possibly shared or independent) of the object managed by
/// this factory.
/// </returns>
public object GetObject()
{
return _builderDelegate.Invoke();
}
/// <summary>
/// Return the <see cref="T:System.Type"/> of object that this
/// <see cref="T:Spring.Objects.Factory.IFactoryObject"/> creates, or
/// <see langword="null"/> if not known in advance.
/// </summary>
public Type ObjectType
{
get { return typeof(T); }
}
/// <summary>
/// Is the object managed by this factory a singleton or a prototype?
/// </summary>
public bool IsSingleton
{
get { return _isSingleton; }
}
}
}

View File

@@ -708,6 +708,7 @@
<Compile Include="Objects\Factory\Parsing\ObjectDefinitionParsingException.cs" />
<Compile Include="Objects\Factory\Parsing\Problem.cs" />
<Compile Include="Objects\Factory\Parsing\ReaderContext.cs" />
<Compile Include="Objects\Factory\Support\DelegatingFactoryObject.cs" />
<Compile Include="Objects\Factory\Support\IObjectDefinitionRegistryPostProcessor.cs" />
<Compile Include="Objects\Factory\Support\ObjectScope.cs" />
<Compile Include="Util\ConstructorInstantiationInfo.cs" />

View File

@@ -710,6 +710,7 @@
<Compile Include="Objects\Factory\Parsing\ObjectDefinitionParsingException.cs" />
<Compile Include="Objects\Factory\Parsing\Problem.cs" />
<Compile Include="Objects\Factory\Parsing\ReaderContext.cs" />
<Compile Include="Objects\Factory\Support\DelegatingFactoryObject.cs" />
<Compile Include="Objects\Factory\Support\IObjectDefinitionRegistryPostProcessor.cs" />
<Compile Include="Objects\Factory\Support\ObjectScope.cs" />
<Compile Include="Util\ConstructorInstantiationInfo.cs" />

View File

@@ -0,0 +1,78 @@
using NUnit.Framework;
using Spring.Context;
using Spring.Context.Support;
namespace Spring.Objects.Factory.Support
{
[TestFixture]
public class DelegatingFactoryObjectTests
{
[SetUp]
public void _TestSetUp()
{
var context = new GenericApplicationContext();
ContextRegistry.Clear();
ContextRegistry.RegisterContext(context);
}
private void RegisterDelegatingFactoryWithContext(bool buildSingletonObjectsWhenInvoked)
{
var targetBuilder = new ThingThatBuildsTargets();
var factory = new DelegatingFactoryObject<TargetToBuild>(targetBuilder.BuildTarget, buildSingletonObjectsWhenInvoked);
Assume.That(ContextRegistry.GetContext(), Is.InstanceOf<IConfigurableApplicationContext>(), "test requires a registered context that implements IConfigurableApplicationContext!");
var ctx = (IConfigurableApplicationContext)ContextRegistry.GetContext();
ctx.ObjectFactory.RegisterSingleton("target", factory);
}
[Test]
public void CanReturnSingletonObjects()
{
RegisterDelegatingFactoryWithContext(true);
var targetObject1 = ContextRegistry.GetContext().GetObject<TargetToBuild>();
var targetObject2 = ContextRegistry.GetContext().GetObject<TargetToBuild>();
Assert.That(targetObject1, Is.SameAs(targetObject2));
Assert.That(targetObject1.Counter, Is.EqualTo(targetObject2.Counter));
}
[Test]
public void CanReturnProtoypeObjects()
{
RegisterDelegatingFactoryWithContext(false);
var targetObject1 = ContextRegistry.GetContext().GetObject<TargetToBuild>();
var targetObject2 = ContextRegistry.GetContext().GetObject<TargetToBuild>();
Assert.That(targetObject1, Is.Not.SameAs(targetObject2));
Assert.That(targetObject1.Counter, Is.Not.EqualTo(targetObject2.Counter));
}
}
public class ThingThatBuildsTargets
{
//since the IFactoryObject impl that contains this is registered w context as singleton,
// this counter is effectively static (sort of! <g>) and will be incremented on each call to build the TARGET instance
private int _counter;
public TargetToBuild BuildTarget()
{
//create and return a new TARGET instance with the incremented counter value to show its working
return new TargetToBuild(_counter++);
}
}
//the type we're trying to tell the container we want to be in charge of creating
public class TargetToBuild
{
public TargetToBuild(int counter)
{
Counter = counter;
}
public int Counter { get; private set; }
}
}

View File

@@ -335,6 +335,7 @@
<Compile Include="Objects\Factory\Config\VariablePlaceholderConfigurerTests.cs" />
<Compile Include="Objects\Factory\DefaultListableObjectFactoryPerfTests.cs" />
<Compile Include="Objects\Factory\DummyConfigurableFactory.cs" />
<Compile Include="Objects\Factory\Support\DelegatingFactoryObjectTests.cs" />
<Compile Include="Objects\Factory\Support\ManagedNameValueCollectionTests.cs" />
<Compile Include="Objects\Factory\Support\ManagedListTests.cs" />
<Compile Include="Objects\Factory\Support\ManagedDictionaryTests.cs" />

View File

@@ -358,6 +358,7 @@
<Compile Include="Objects\LazyTestObject.cs" />
<Compile Include="Objects\Support\AbstractSharedStateFactoryTests.cs" />
<Compile Include="Objects\Support\ByTypeSharedStateProviderTests.cs" />
<Compile Include="Objects\Support\DelegatingFactoryObjectTests.cs" />
<Compile Include="Objects\Support\MethodInvokerTests.cs">
<SubType>Code</SubType>
</Compile>