See: Description
Class | Description |
---|---|
BaseEntity<I> |
This is the base class for any set of classes that self-insert themselves into a Factory upon instantiation
The way it works that a user will need to create an Interface and an abstract class implementing this Interface.
|
BaseEntityFactory<I> |
This is the parent factory class for all the factories.
|
BaseEntityFactory
and BaseEntity
. In short
what this infrastructure does is that if you create a factory that extends
BaseEntityFactory
and some Interface with all its concrete implementations
extending BaseEntity
then each your concrete implementation class instances will be
automatically inserted into your factory. You won't have to worry about how and when to populate your factory. The
infrastructure will do it for you when the constructor of your concrete implementation class is invoked. So all you
will have to do is to create any number of concrete implementation classes and make sure that for each one constructor
is invoked. After that you can use your factory to get any of your concrete implementation classes anywhere in your code.
This is short explanation. There are few more details but not that many.
Lets show it with an example. This infrastructure has Package com.mgnt.lifecycle.management.example
that has some sub-packages that contains source code example that demonstrate how this infrastructure is used. So in
this javadoc the same classes will be used. Please see the source code of that package to get all the details.
Say you have an Interface called
InfoFormatter
that has a single method
InfoFormatter.formatMessage(java.lang.String)
. Obviously this method
takes some text and formats it according some logic that would be implemented in each concrete implementation.
Next we need to create a factory for our concrete implementations. So we have a factory class
InfoFormatterFactory
that extends
BaseEntityFactory
This class look like this:
package com.mgnt.lifecycle.management.example;
import com.mgnt.lifecycle.management.BaseEntityFactory;
import java.util.Collection;
public class InfoFormatterFactory extends BaseEntityFactory<InfoFormatter> {
private static InfoFormatterFactory FACTORY = new InfoFormatterFactory();
private InfoFormatterFactory() {
}
public static InfoFormatterFactory getFactoryInstance() {
return FACTORY;
}
public static InfoFormatter getInstance(String key) {
return FACTORY.getEntity(key);
}
public static Collection<InfoFormatter> getAllInstances() {
return FACTORY.getAllEntities();
}
}
BaseEntity
and implementing your interface is created. Then all your concrete
implementations will extend this class. So in our case we will have
BaseInfoFormatter
that extends BaseEntity
and implements InfoFormatter
.
This class should look like this:
public abstract class BaseInfoFormatter extends BaseEntity<BaseInfoFormatter> implements InfoFormatter {
// This is mandatory part of the code for the infrastructure to work
private static final String FACTORY_TYPE = BaseInfoFormatter.class.getSimpleName();
static {
init(FACTORY_TYPE, InfoFormatterFactory.getFactoryInstance());
}
public BaseInfoFormatter() {
super(FACTORY_TYPE);
}
public BaseInfoFormatter(String customName) {
super(FACTORY_TYPE, customName);
}
// The end of mandatory part
// Some business logic methods that are common to all concrete implementations
//...
//Implementation of interface declared method
//...
}
JsonInfoFormatter
and XmlInfoFormatter
(both of them extending their abstract
parent class BaseInfoFormatter
). Here is how one of them might look,
(the second looks very similar so it is ommitted here)
public class JsonInfoFormatter extends BaseInfoFormatter {
private final static String CUSTOM_NAME = "JSON";
public JsonInfoFormatter() {
super(CUSTOM_NAME);
}
//Implementation of abstract method or overriding methods goes here
}
UsageExample
and in particular its methods
UsageExample.init()
(that is invoked in the main()
method) and looks as folllows
private static void init() {
new JsonInfoFormatter();
new XmlInfoFormatter();
}
UsageExample.printFormattedGreetings()
that looks
as follows
private static void printFormattedGreetings() {
InfoFormatter formatter = InfoFormatterFactory.getInstance("JSON");
System.out.println("JSON greeting: " + formatter.formatMessage(MESSAGE));
formatter = InfoFormatterFactory.getInstance("XML");
System.out.println("XML greeting: " + formatter.formatMessage(MESSAGE));
List<String> allMessages = new ArrayList<>();
for(InfoFormatter formattedMessage : InfoFormatterFactory.getAllInstances()) {
allMessages.add(formattedMessage.formatMessage(MESSAGE));
}
System.out.println("All greetings: " + allMessages);
}
InfoFormatterFactory.getInstance(java.lang.String)
to get ahold of our concrete implementations. This works because method init was invoked before. Note that in init method
we simply instantiate our concrete implementations and not saving any references to them. Thanks to the infrastructure,
during its instantiation each instance inserted itself into its factory and that allows it to be accessed through the
factory. As for the names ("XML" and "JSON") they are in our case defined in each concrete class and passed to the factory
through use of its parent constructor
BaseInfoFormatter.BaseInfoFormatter(java.lang.String)
which in turn will
invoke its parent constructor BaseEntity.BaseEntity(java.lang.String, java.lang.String)
.
However, BaseEntity
provides another constructor
BaseEntity.BaseEntity(java.lang.String)
where custom name for entity is not
required. And the entity would be registered in its factory by its class name.
That was about how this infrastructure works. Now where would it be convenient and beneficial to use it? Note that in order
for infrastructure to work we had to invoke constructor for each concrete class. If only someone or something could
have done that for us, that would be magical. Well, this could be done for us by Spring framework. Remember that Spring
instantiate all it's defined beans during its initialization. So within Spring context if we simply declare our concrete
implementations as Spring beans, Spring would instantiate them for us, thus initializing their factory automatically.
This could be very convenient. Imagine that you have some bean that has a property of type
InfoFormatter
, but which actual implementation would be needed is determined
at runtime. So at that moment you can use
InfoFormatterFactory.getInstance(java.lang.String)
to access needed
implementation. This will allow you not to inject ALL your concrete instantiations into your bean and you won't have to
use Spring BeanFactory to access a Spring defined bean as that would violate non-intrusiveness of Spring (meaning
you can write components which have no dependency on Spring). Also, If at some later stage you will need to add
more concrete implementations, all you will have to do is to add your implementation classes to you code and declare
them to be Spring beans. The rest will be done by Spring and this infrastructure!