mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Add registration linking
This commit is contained in:
parent
fe6a62104e
commit
eb05f7702f
|
@ -1,151 +1,162 @@
|
|||
/**
|
||||
* This module contains objects for defining and scoping dependency registrations.
|
||||
*
|
||||
* Part of the Poodinis Dependency Injection framework.
|
||||
*
|
||||
* Authors:
|
||||
* Mike Bierlee, m.bierlee@lostmoment.com
|
||||
* Copyright: 2014-2015 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.registration;
|
||||
|
||||
debug {
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
}
|
||||
|
||||
class Registration {
|
||||
TypeInfo registeredType = null;
|
||||
TypeInfo_Class instantiatableType = null;
|
||||
CreationScope registationScope = null;
|
||||
|
||||
this(TypeInfo registeredType, TypeInfo_Class instantiatableType) {
|
||||
this.registeredType = registeredType;
|
||||
this.instantiatableType = instantiatableType;
|
||||
}
|
||||
|
||||
public Object getInstance(InstantiationContext context = new InstantiationContext()) {
|
||||
if (registationScope is null) {
|
||||
throw new NoScopeDefinedException(registeredType);
|
||||
}
|
||||
|
||||
return registationScope.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
class NoScopeDefinedException : Exception {
|
||||
this(TypeInfo type) {
|
||||
super("No scope defined for registration of type " ~ type.toString());
|
||||
}
|
||||
}
|
||||
|
||||
interface CreationScope {
|
||||
public Object getInstance();
|
||||
}
|
||||
|
||||
class NullScope : CreationScope {
|
||||
public Object getInstance() {
|
||||
debug(poodinisVerbose) {
|
||||
writeln("DEBUG: No instance created (NullScope)");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SingleInstanceScope : CreationScope {
|
||||
TypeInfo_Class instantiatableType = null;
|
||||
Object instance = null;
|
||||
|
||||
this(TypeInfo_Class instantiatableType) {
|
||||
this.instantiatableType = instantiatableType;
|
||||
}
|
||||
|
||||
public Object getInstance() {
|
||||
if (instance is null) {
|
||||
debug(poodinisVerbose) {
|
||||
writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
|
||||
}
|
||||
instance = instantiatableType.create();
|
||||
} else {
|
||||
debug(poodinisVerbose) {
|
||||
writeln(format("DEBUG: Existing instance returned of type %s (SingleInstanceScope)", instantiatableType.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes registrations to return the same instance every time a given registration is resolved.
|
||||
*
|
||||
* Effectively makes the given registration a singleton.
|
||||
*/
|
||||
public Registration singleInstance(Registration registration) {
|
||||
registration.registationScope = new SingleInstanceScope(registration.instantiatableType);
|
||||
return registration;
|
||||
}
|
||||
|
||||
class NewInstanceScope : CreationScope {
|
||||
TypeInfo_Class instantiatableType = null;
|
||||
|
||||
this(TypeInfo_Class instantiatableType) {
|
||||
this.instantiatableType = instantiatableType;
|
||||
}
|
||||
|
||||
public Object getInstance() {
|
||||
debug(poodinisVerbose) {
|
||||
writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
|
||||
}
|
||||
return instantiatableType.create();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes registrations to return a new instance every time the given registration is resolved.
|
||||
*/
|
||||
public Registration newInstance(Registration registration) {
|
||||
registration.registationScope = new NewInstanceScope(registration.instantiatableType);
|
||||
return registration;
|
||||
}
|
||||
|
||||
class ExistingInstanceScope : CreationScope {
|
||||
Object instance = null;
|
||||
|
||||
this(Object instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public Object getInstance() {
|
||||
debug(poodinisVerbose) {
|
||||
writeln("DEBUG: Existing instance returned (ExistingInstanceScope)");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes registrations to return the given instance every time the given registration is resolved.
|
||||
*/
|
||||
public Registration existingInstance(Registration registration, Object instance) {
|
||||
registration.registationScope = new ExistingInstanceScope(instance);
|
||||
return registration;
|
||||
}
|
||||
|
||||
public string toConcreteTypeListString(Registration[] registrations) {
|
||||
auto concreteTypeListString = "";
|
||||
foreach (registration ; registrations) {
|
||||
if (concreteTypeListString.length > 0) {
|
||||
concreteTypeListString ~= ", ";
|
||||
}
|
||||
concreteTypeListString ~= registration.instantiatableType.toString();
|
||||
}
|
||||
return concreteTypeListString;
|
||||
}
|
||||
|
||||
class InstantiationContext {}
|
||||
/**
|
||||
* This module contains objects for defining and scoping dependency registrations.
|
||||
*
|
||||
* Part of the Poodinis Dependency Injection framework.
|
||||
*
|
||||
* Authors:
|
||||
* Mike Bierlee, m.bierlee@lostmoment.com
|
||||
* Copyright: 2014-2015 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.registration;
|
||||
|
||||
debug {
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
}
|
||||
|
||||
class Registration {
|
||||
TypeInfo registeredType = null;
|
||||
TypeInfo_Class instantiatableType = null;
|
||||
CreationScope registationScope = null;
|
||||
private Registration linkedRegistration;
|
||||
|
||||
this(TypeInfo registeredType, TypeInfo_Class instantiatableType) {
|
||||
this.registeredType = registeredType;
|
||||
this.instantiatableType = instantiatableType;
|
||||
}
|
||||
|
||||
public Object getInstance(InstantiationContext context = new InstantiationContext()) {
|
||||
if (linkedRegistration !is null) {
|
||||
return linkedRegistration.getInstance(context);
|
||||
}
|
||||
|
||||
|
||||
if (registationScope is null) {
|
||||
throw new NoScopeDefinedException(registeredType);
|
||||
}
|
||||
|
||||
return registationScope.getInstance();
|
||||
}
|
||||
|
||||
public Registration linkTo(Registration registration) {
|
||||
this.linkedRegistration = registration;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class NoScopeDefinedException : Exception {
|
||||
this(TypeInfo type) {
|
||||
super("No scope defined for registration of type " ~ type.toString());
|
||||
}
|
||||
}
|
||||
|
||||
interface CreationScope {
|
||||
public Object getInstance();
|
||||
}
|
||||
|
||||
class NullScope : CreationScope {
|
||||
public Object getInstance() {
|
||||
debug(poodinisVerbose) {
|
||||
writeln("DEBUG: No instance created (NullScope)");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SingleInstanceScope : CreationScope {
|
||||
TypeInfo_Class instantiatableType = null;
|
||||
Object instance = null;
|
||||
|
||||
this(TypeInfo_Class instantiatableType) {
|
||||
this.instantiatableType = instantiatableType;
|
||||
}
|
||||
|
||||
public Object getInstance() {
|
||||
if (instance is null) {
|
||||
debug(poodinisVerbose) {
|
||||
writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
|
||||
}
|
||||
instance = instantiatableType.create();
|
||||
} else {
|
||||
debug(poodinisVerbose) {
|
||||
writeln(format("DEBUG: Existing instance returned of type %s (SingleInstanceScope)", instantiatableType.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes registrations to return the same instance every time a given registration is resolved.
|
||||
*
|
||||
* Effectively makes the given registration a singleton.
|
||||
*/
|
||||
public Registration singleInstance(Registration registration) {
|
||||
registration.registationScope = new SingleInstanceScope(registration.instantiatableType);
|
||||
return registration;
|
||||
}
|
||||
|
||||
class NewInstanceScope : CreationScope {
|
||||
TypeInfo_Class instantiatableType = null;
|
||||
|
||||
this(TypeInfo_Class instantiatableType) {
|
||||
this.instantiatableType = instantiatableType;
|
||||
}
|
||||
|
||||
public Object getInstance() {
|
||||
debug(poodinisVerbose) {
|
||||
writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
|
||||
}
|
||||
return instantiatableType.create();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes registrations to return a new instance every time the given registration is resolved.
|
||||
*/
|
||||
public Registration newInstance(Registration registration) {
|
||||
registration.registationScope = new NewInstanceScope(registration.instantiatableType);
|
||||
return registration;
|
||||
}
|
||||
|
||||
class ExistingInstanceScope : CreationScope {
|
||||
Object instance = null;
|
||||
|
||||
this(Object instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public Object getInstance() {
|
||||
debug(poodinisVerbose) {
|
||||
writeln("DEBUG: Existing instance returned (ExistingInstanceScope)");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scopes registrations to return the given instance every time the given registration is resolved.
|
||||
*/
|
||||
public Registration existingInstance(Registration registration, Object instance) {
|
||||
registration.registationScope = new ExistingInstanceScope(instance);
|
||||
return registration;
|
||||
}
|
||||
|
||||
public string toConcreteTypeListString(Registration[] registrations) {
|
||||
auto concreteTypeListString = "";
|
||||
foreach (registration ; registrations) {
|
||||
if (concreteTypeListString.length > 0) {
|
||||
concreteTypeListString ~= ", ";
|
||||
}
|
||||
concreteTypeListString ~= registration.instantiatableType.toString();
|
||||
}
|
||||
return concreteTypeListString;
|
||||
}
|
||||
|
||||
class InstantiationContext {}
|
||||
|
|
|
@ -1,80 +1,94 @@
|
|||
/**
|
||||
* Poodinis Dependency Injection Framework
|
||||
* Copyright 2014-2015 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.registration;
|
||||
|
||||
import std.exception;
|
||||
|
||||
version(unittest) {
|
||||
class TestType {
|
||||
}
|
||||
|
||||
// Test getting instance without scope defined throws exception
|
||||
unittest {
|
||||
/**
|
||||
* Poodinis Dependency Injection Framework
|
||||
* Copyright 2014-2015 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.registration;
|
||||
|
||||
import std.exception;
|
||||
|
||||
version(unittest) {
|
||||
class TestType {}
|
||||
|
||||
interface TestInterface {}
|
||||
|
||||
class TestImplementation : TestInterface {}
|
||||
|
||||
// Test getting instance without scope defined throws exception
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
registration.registeredType = typeid(TestType);
|
||||
assertThrown!(NoScopeDefinedException)(registration.getInstance());
|
||||
}
|
||||
|
||||
// Test getting instance from single instance scope
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
registration.registationScope = new SingleInstanceScope(typeid(TestType));
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 is instance2, "Registration with single instance scope did not return the same instance");
|
||||
}
|
||||
|
||||
// Test set single instance scope using scope setter
|
||||
unittest {
|
||||
Registration registration = new Registration(null, typeid(TestType));
|
||||
auto chainedRegistration = registration.singleInstance();
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 is instance2, "Registration with single instance scope did not return the same instance");
|
||||
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
|
||||
}
|
||||
|
||||
// Test getting instance from new instance scope
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
registration.registationScope = new NewInstanceScope(typeid(TestType));
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 !is instance2, "Registration with new instance scope did not return a different instance");
|
||||
}
|
||||
|
||||
// Test set new instance scope using scope setter
|
||||
unittest {
|
||||
Registration registration = new Registration(null, typeid(TestType));
|
||||
auto chainedRegistration = registration.newInstance();
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 !is instance2, "Registration with new instance scope did not return a different instance");
|
||||
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
|
||||
}
|
||||
|
||||
// Test getting instance from existing instance scope
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
TestType expectedInstance = new TestType();
|
||||
registration.registationScope = new ExistingInstanceScope(expectedInstance);
|
||||
auto actualInstance = registration.getInstance();
|
||||
assert(expectedInstance is actualInstance, "Registration with existing instance did not return given instance");
|
||||
}
|
||||
|
||||
// Test set existing instance scope using scope setter
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
auto expectedInstance = new TestType();
|
||||
auto chainedRegistration = registration.existingInstance(expectedInstance);
|
||||
auto actualInstance = registration.getInstance();
|
||||
assert(expectedInstance is expectedInstance, "Registration with existing instance scope did not return the same instance");
|
||||
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
|
||||
}
|
||||
|
||||
}
|
||||
assertThrown!(NoScopeDefinedException)(registration.getInstance());
|
||||
}
|
||||
|
||||
// Test getting instance from single instance scope
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
registration.registationScope = new SingleInstanceScope(typeid(TestType));
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 is instance2, "Registration with single instance scope did not return the same instance");
|
||||
}
|
||||
|
||||
// Test set single instance scope using scope setter
|
||||
unittest {
|
||||
Registration registration = new Registration(null, typeid(TestType));
|
||||
auto chainedRegistration = registration.singleInstance();
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 is instance2, "Registration with single instance scope did not return the same instance");
|
||||
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
|
||||
}
|
||||
|
||||
// Test getting instance from new instance scope
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
registration.registationScope = new NewInstanceScope(typeid(TestType));
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 !is instance2, "Registration with new instance scope did not return a different instance");
|
||||
}
|
||||
|
||||
// Test set new instance scope using scope setter
|
||||
unittest {
|
||||
Registration registration = new Registration(null, typeid(TestType));
|
||||
auto chainedRegistration = registration.newInstance();
|
||||
auto instance1 = registration.getInstance();
|
||||
auto instance2 = registration.getInstance();
|
||||
assert(instance1 !is instance2, "Registration with new instance scope did not return a different instance");
|
||||
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
|
||||
}
|
||||
|
||||
// Test getting instance from existing instance scope
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
TestType expectedInstance = new TestType();
|
||||
registration.registationScope = new ExistingInstanceScope(expectedInstance);
|
||||
auto actualInstance = registration.getInstance();
|
||||
assert(expectedInstance is actualInstance, "Registration with existing instance did not return given instance");
|
||||
}
|
||||
|
||||
// Test set existing instance scope using scope setter
|
||||
unittest {
|
||||
Registration registration = new Registration(null, null);
|
||||
auto expectedInstance = new TestType();
|
||||
auto chainedRegistration = registration.existingInstance(expectedInstance);
|
||||
auto actualInstance = registration.getInstance();
|
||||
assert(expectedInstance is expectedInstance, "Registration with existing instance scope did not return the same instance");
|
||||
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
|
||||
}
|
||||
|
||||
// Test linking registrations
|
||||
unittest {
|
||||
Registration firstRegistration = new Registration(typeid(TestInterface), typeid(TestImplementation)).singleInstance();
|
||||
Registration secondRegistration = new Registration(typeid(TestImplementation), typeid(TestImplementation)).singleInstance().linkTo(firstRegistration);
|
||||
|
||||
auto firstInstance = firstRegistration.getInstance();
|
||||
auto secondInstance = secondRegistration.getInstance();
|
||||
|
||||
assert(firstInstance is secondInstance);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue