All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.main.java.com.mgnt.lifecycle.management.package-info Maven / Gradle / Ivy

/**
 * This package contains some small infrastructure that simplifies and automates working with Factories that provide
 * concrete implementations of an Interface. The package contains just 2 classes:
 * {@link com.mgnt.lifecycle.management.BaseEntityFactory} and {@link com.mgnt.lifecycle.management.BaseEntity}. In short
 * what this infrastructure does is that if you create a factory that extends
 * {@link com.mgnt.lifecycle.management.BaseEntityFactory} and some Interface with all its concrete implementations
 * extending {@link com.mgnt.lifecycle.management.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 {@code 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 * {@link com.mgnt.lifecycle.management.example.InfoFormatter} that has a single method * {@link com.mgnt.lifecycle.management.example.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 * {@link com.mgnt.lifecycle.management.example.InfoFormatterFactory} that extends * {@link com.mgnt.lifecycle.management.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();
*   }
* }
*

*

* * * For the purposes of this infrastructure it is recommended that a single abstract parent class extending * {@link com.mgnt.lifecycle.management.BaseEntity} and implementing your interface is created. Then all your concrete * implementations will extend this class. So in our case we will have * {@link com.mgnt.lifecycle.management.example.BaseInfoFormatter} that extends {@link com.mgnt.lifecycle.management.BaseEntity} * and implements {@link com.mgnt.lifecycle.management.example.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
*      //...
*   }
*

* * Then we have 2 concrete implementations: {@link com.mgnt.lifecycle.management.example.implementations.JsonInfoFormatter} * and {@link com.mgnt.lifecycle.management.example.implementations.XmlInfoFormatter} (both of them extending their abstract * parent class {@link com.mgnt.lifecycle.management.example.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
*   }
*

* * So this is our row material so to speak. * So lets see how this is used. Look at the class * {@link com.mgnt.lifecycle.management.example.implementations.usage.UsageExample} and in particular its methods * {@link com.mgnt.lifecycle.management.example.implementations.usage.UsageExample#init()} (that is invoked in the main() * method) and looks as folllows *


*    private static void init() {
*      new JsonInfoFormatter();
*      new XmlInfoFormatter();
*    }
*
*


* and * {@link com.mgnt.lifecycle.management.example.implementations.usage.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);
*    }
*
*

* Note that we simply use {@link com.mgnt.lifecycle.management.example.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 * {@link com.mgnt.lifecycle.management.example.BaseInfoFormatter#BaseInfoFormatter(java.lang.String)} which in turn will * invoke its parent constructor {@link com.mgnt.lifecycle.management.BaseEntity#BaseEntity(java.lang.String, java.lang.String)}. * However, {@link com.mgnt.lifecycle.management.BaseEntity} provides another constructor * {@link com.mgnt.lifecycle.management.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 * {@link com.mgnt.lifecycle.management.example.InfoFormatter}, but which actual implementation would be needed is determined * at runtime. So at that moment you can use * {@link com.mgnt.lifecycle.management.example.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! *

*/ package com.mgnt.lifecycle.management;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy