diff --git a/source/poodinis/autowire.d b/source/poodinis/autowire.d index a579561..58411e0 100644 --- a/source/poodinis/autowire.d +++ b/source/poodinis/autowire.d @@ -19,6 +19,7 @@ module poodinis.autowire; import poodinis.container; import poodinis.registration; +import poodinis.factory; import std.exception; import std.stdio; diff --git a/source/poodinis/context.d b/source/poodinis/context.d index 8e27af8..2864929 100644 --- a/source/poodinis/context.d +++ b/source/poodinis/context.d @@ -15,6 +15,7 @@ module poodinis.context; import poodinis.container; import poodinis.registration; +import poodinis.factory; import std.traits; diff --git a/source/poodinis/factory.d b/source/poodinis/factory.d new file mode 100644 index 0000000..638739c --- /dev/null +++ b/source/poodinis/factory.d @@ -0,0 +1,65 @@ +/** + * This module contains instance factory facilities + * + * Authors: + * Mike Bierlee, m.bierlee@lostmoment.com + * Copyright: 2014-2016 Mike Bierlee + * License: + * This software is licensed under the terms of the MIT license. + * The full terms of the license can be found in the LICENSE file. + */ + +module poodinis.factory; + +import std.typecons; +import std.exception; + +debug { + import std.string; + import std.stdio; +} + +alias CreatesSingleton = Flag!"CreatesSingleton"; +alias InstanceFactoryMethod = Object delegate(); + +class InstanceCreationException : Exception { + this(string message, string file = __FILE__, size_t line = __LINE__) { + super(message, file, line); + } +} + +class InstanceFactory { + private TypeInfo_Class instanceType = null; + private Object instance = null; + private CreatesSingleton createsSingleton; + private InstanceFactoryMethod factoryMethod; + + this(TypeInfo_Class instanceType, CreatesSingleton createsSingleton = CreatesSingleton.yes, Object existingInstance = null, InstanceFactoryMethod factoryMethod = null) { + this.instanceType = instanceType; + this.createsSingleton = existingInstance !is null ? CreatesSingleton.yes : createsSingleton; + this.instance = existingInstance; + this.factoryMethod = factoryMethod !is null ? factoryMethod : &this.createInstance; + } + + public Object getInstance() { + if (createsSingleton && instance !is null) { + debug(poodinisVerbose) { + writeln(format("DEBUG: Existing instance returned of type %s", instanceType.toString())); + } + + return instance; + } + + debug(poodinisVerbose) { + writeln(format("DEBUG: Creating new instance of type %s", instanceType.toString())); + } + + instance = factoryMethod(); + return instance; + } + + private Object createInstance() { + enforce!InstanceCreationException(instanceType, "Instance type is not defined, cannot create instance without knowing its type."); + return instanceType.create(); + } +} diff --git a/source/poodinis/package.d b/source/poodinis/package.d index 30db364..3cffcbe 100644 --- a/source/poodinis/package.d +++ b/source/poodinis/package.d @@ -15,3 +15,4 @@ public import poodinis.autowire; public import poodinis.container; public import poodinis.registration; public import poodinis.context; +public import poodinis.factory; diff --git a/source/poodinis/registration.d b/source/poodinis/registration.d index 26fa684..e451a9b 100644 --- a/source/poodinis/registration.d +++ b/source/poodinis/registration.d @@ -14,20 +14,7 @@ module poodinis.registration; import poodinis.container; - -import std.typecons; -import std.exception; - -debug { - import std.stdio; - import std.string; -} - -class InstanceCreationException : Exception { - this(string message, string file = __FILE__, size_t line = __LINE__) { - super(message, file, line); - } -} +import poodinis.factory; class Registration { private TypeInfo _registeredType = null; @@ -74,45 +61,6 @@ class Registration { } } -alias CreatesSingleton = Flag!"CreatesSingleton"; -alias InstanceFactoryMethod = Object delegate(); - -class InstanceFactory { - private TypeInfo_Class instanceType = null; - private Object instance = null; - private CreatesSingleton createsSingleton; - private InstanceFactoryMethod factoryMethod; - - this(TypeInfo_Class instanceType, CreatesSingleton createsSingleton = CreatesSingleton.yes, Object existingInstance = null, InstanceFactoryMethod factoryMethod = null) { - this.instanceType = instanceType; - this.createsSingleton = existingInstance !is null ? CreatesSingleton.yes : createsSingleton; - this.instance = existingInstance; - this.factoryMethod = factoryMethod !is null ? factoryMethod : &this.createInstance; - } - - public Object getInstance() { - if (createsSingleton && instance !is null) { - debug(poodinisVerbose) { - writeln(format("DEBUG: Existing instance returned of type %s", instanceType.toString())); - } - - return instance; - } - - debug(poodinisVerbose) { - writeln(format("DEBUG: Creating new instance of type %s", instanceType.toString())); - } - - instance = factoryMethod(); - return instance; - } - - private Object createInstance() { - enforce!InstanceCreationException(instanceType, "Instance type is not defined, cannot create instance without knowing its type."); - return instanceType.create(); - } -} - /** * Scopes registrations to return the same instance every time a given registration is resolved. * diff --git a/test/poodinis/factorytest.d b/test/poodinis/factorytest.d new file mode 100644 index 0000000..7fe0e9f --- /dev/null +++ b/test/poodinis/factorytest.d @@ -0,0 +1,72 @@ +/** + * Poodinis Dependency Injection Framework + * Copyright 2014-2016 Mike Bierlee + * This software is licensed under the terms of the MIT license. + * The full terms of the license can be found in the LICENSE file. + */ + +import poodinis; + +version(unittest) { + + interface TestInterface {} + + class TestImplementation : TestInterface { + public string someContent = ""; + } + + // Test instance factory with singletons + unittest { + auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.yes, null); + auto instanceOne = factory.getInstance(); + auto instanceTwo = factory.getInstance(); + + assert(instanceOne !is null, "Created factory instance is null"); + assert(instanceOne is instanceTwo, "Created factory instance is not the same"); + } + + // Test instance factory with new instances + unittest { + auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.no, null); + auto instanceOne = factory.getInstance(); + auto instanceTwo = factory.getInstance(); + + assert(instanceOne !is null, "Created factory instance is null"); + assert(instanceOne !is instanceTwo, "Created factory instance is the same"); + } + + // Test instance factory with existing instances + unittest { + auto existingInstance = new TestImplementation(); + auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.yes, existingInstance); + auto instanceOne = factory.getInstance(); + auto instanceTwo = factory.getInstance(); + + assert(instanceOne is existingInstance, "Created factory instance is not the existing instance"); + assert(instanceTwo is existingInstance, "Created factory instance is not the existing instance when called again"); + } + + // Test instance factory with existing instances when setting singleton flag to "no" + unittest { + auto existingInstance = new TestImplementation(); + auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.no, existingInstance); + auto instance = factory.getInstance(); + + assert(instance is existingInstance, "Created factory instance is not the existing instance"); + } + + // Test creating instance using custom factory method + unittest { + Object factoryMethod() { + auto instance = new TestImplementation(); + instance.someContent = "Ducks!"; + return instance; + } + + auto factory = new InstanceFactory(null, CreatesSingleton.yes, null, &factoryMethod); + auto instance = cast(TestImplementation) factory.getInstance(); + + assert(instance !is null, "No instance was created by factory or could not be cast to expected type"); + assert(instance.someContent == "Ducks!"); + } +} diff --git a/test/poodinis/registrationtest.d b/test/poodinis/registrationtest.d index 6c3ef77..f21474f 100644 --- a/test/poodinis/registrationtest.d +++ b/test/poodinis/registrationtest.d @@ -65,59 +65,4 @@ version(unittest) { assert(firstInstance is secondInstance); } - // Test instance factory with singletons - unittest { - auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.yes, null); - auto instanceOne = factory.getInstance(); - auto instanceTwo = factory.getInstance(); - - assert(instanceOne !is null, "Created factory instance is null"); - assert(instanceOne is instanceTwo, "Created factory instance is not the same"); - } - - // Test instance factory with new instances - unittest { - auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.no, null); - auto instanceOne = factory.getInstance(); - auto instanceTwo = factory.getInstance(); - - assert(instanceOne !is null, "Created factory instance is null"); - assert(instanceOne !is instanceTwo, "Created factory instance is the same"); - } - - // Test instance factory with existing instances - unittest { - auto existingInstance = new TestImplementation(); - auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.yes, existingInstance); - auto instanceOne = factory.getInstance(); - auto instanceTwo = factory.getInstance(); - - assert(instanceOne is existingInstance, "Created factory instance is not the existing instance"); - assert(instanceTwo is existingInstance, "Created factory instance is not the existing instance when called again"); - } - - // Test instance factory with existing instances when setting singleton flag to "no" - unittest { - auto existingInstance = new TestImplementation(); - auto factory = new InstanceFactory(typeid(TestImplementation), CreatesSingleton.no, existingInstance); - auto instance = factory.getInstance(); - - assert(instance is existingInstance, "Created factory instance is not the existing instance"); - } - - // Test creating instance using custom factory method - unittest { - Object factoryMethod() { - auto instance = new TestImplementation(); - instance.someContent = "Ducks!"; - return instance; - } - - auto factory = new InstanceFactory(null, CreatesSingleton.yes, null, &factoryMethod); - auto instance = cast(TestImplementation) factory.getInstance(); - - assert(instance !is null, "No instance was created by factory or could not be cast to expected type"); - assert(instance.someContent == "Ducks!"); - } - }