Design patterns help to follow good programming practices. The Spring framework, one of the most popular Web frameworks, also uses some of these. Of course, this was covered in the previous article design Patterns. This article introduces the design patterns used in the Spring Framework. This is the first of five feature articles. This time we’ll discover four design patterns used in the Spring framework: interpreter, builder, factory method, and Abstract factory. Each section will first explain the rationale for a given pattern. Next, you’ll use an example from Spring to deepen your understanding.

Interpreter design patterns

In the real world, we humans need to interpret gestures. They can mean different things to the culture. This is our interpretation, to give them meaning. In programming, there is one more thing we need to analyze and decide what it means. We can do this by explaining design patterns. This pattern is based on the expression and evaluator sections. The first one represents a matter to be analyzed. This analysis is done by evaluators who know the meaning of the characters that constitute the expression. Unnecessary operations are performed in a context. The Spring Expression Language (Spel) is used as an example. Quick reminder here, SpEL is composed of Spring’s org. Springframework. Expression. ExpressionParser implementation language analysis and execution. These implementations use as a string of Spel expression, and convert them to org. Springframework. Expression. The expression instance. Contextual components by the org. Springframework. Expression. EvaluationContext said, for example: StandardEvaluationContext. Here’s an example from Spel:

Writer writer = new Writer();

writer.setName("Writer's name");

StandardEvaluationContext modifierContext = new StandardEvaluationContext(subscriberContext);

modifierContext.setVariable("name", "Overriden writer's name");

parser.parseExpression("name = #name").getValue(modifierContext);

System.out.println("writer's name is : " + writer.getName());Copy the code

The output should be Overriden writer’s name. As you can see, the attributes of an object are modified with an expression name = #name, which is only understood with ExpressionParser because context is provided (modifierContext instance in the previous example).

Builder pattern

The Builder design pattern is the first pattern that belongs to the three musketeers who create object patterns. This pattern is used to simplify the construction of complex objects. To understand this concept, imagine an object describing a programmer’s resume. In this object, we want to store personal information (name, address, etc.) as well as technical information (language of knowledge, implemented projects, etc.). The object might be constructed as follows:

// with constructor

Programmer programmer = new Programmer("first name", "last name", "address Street 39", "ZIP code", "City", "Country", birthDateObject, new String[] {"Java", "PHP", "Perl", "SQL"}, new String[] {"CRM system", "CMS system for government"});

// or with setters

Programmer programmer = new Programmer();

programmer.setName("first name");

programmer.setLastName("last name");

// ... multiple lines after

programmer.setProjects(new String[] {"CRM system", "CMS system for government"});Copy the code

Builder allows us to decompose object constructs cleanly by using internal Builder objects that pass values to the parent class. So for the creation of our programmer’s resume object, the builder could look something like:

public class BuilderTest{ @Test public void test(){ Programmer programmer = new Programmer.ProgrammerBuilder().setFirstName("F").setLastName("L") .setCity("City").setZipCode("0000A").setAddress("Street 39") .setLanguages(new String[] {"bash", "Perl"}).setProjects(new String[] {"Linux kernel"}).build(); assertTrue("Programmer should be 'F L' but was '"+ programmer+"'", programmer.toString().equals("F L")); } } class Programmer{ private String firstName; private String lastName; private String address; private String zipCode; private String city; private String[] languages; private String[] projects; private Programmer(String fName, String lName, String addr, String zip, String city, String[] langs, String[] projects){ this.firstName = fName; this.lastName = lName; this.address = addr; this.zipCode = zip; this.city = city; this.languages = langs; this.projects = projects; } public static class ProgrammerBuilder{ private String firstName; private String lastName; private String address; private String zipCode; private String city; private String[] languages; private String[] projects; public ProgrammerBuilder setFirstName(String firstName){ this.firstName = firstName; return this; } public ProgrammerBuilder setLastName(String lastName){ this.lastName = lastName; return this; } public ProgrammerBuilder setAddress(String address){ this.address = address; return this; } public ProgrammerBuilder setZipCode(String zipCode){ this.zipCode = zipCode; return this; } public ProgrammerBuilder setCity(String city){ this.city = city; return this; } public ProgrammerBuilder setLanguages(String[] languages){ this.languages = languages; return this; } public ProgrammerBuilder setProjects(String[] projects){ this.projects = projects; return this; } public Programmer build(){ return new Programmer(firstName, lastName, address, zipCode, city, languages, projects); } } @Override public String toString(){ return this.firstName + " "+this.lastName; }}Copy the code

As you can see, the complexity of object construction is hidden behind the builder, and the internal static classes accept calls to linked methods. In Spring, we can in the org. Springframework. Beans. Factory. Support. BeanDefinitionBuilder class to retrieve the logic. This is a class that allows us to programmatically define beans. We saw it in our article on bean factory postprocessors. BeanDefinitionBuilder contains methods that set values for the relevant implementation of an AbstractBeanDefinition abstract class, such as scopes, factory methods, properties, and so on. To see how it works, check out these methods:

public class BeanDefinitionBuilder{

       /**

    * The {@code BeanDefinition} instance we are creating.

    */

  private AbstractBeanDefinition beanDefinition;



  // ... some not important methods for this article



  // Some of building methods

  /**

    * Set the name of the parent definition of this bean definition.

    */

  public BeanDefinitionBuilder setParentName(String parentName){

    this.beanDefinition.setParentName(parentName);

    return this;

  }



  /**

    * Set the name of the factory method to use for this definition.

    */

  public BeanDefinitionBuilder setFactoryMethod(String factoryMethod){

    this.beanDefinition.setFactoryMethodName(factoryMethod);

    return this;

  }



  /**

    * Add an indexed constructor arg value. The current index is tracked internally

    * and all additions are at the present point.

    * @deprecated since Spring 2.5, in favor of {@link #addConstructorArgValue}

    */

  @Deprecated

  public BeanDefinitionBuilder addConstructorArg(Object value){

    return addConstructorArgValue(value);

  }



  /**

    * Add an indexed constructor arg value. The current index is tracked internally

    * and all additions are at the present point.

    */

  public BeanDefinitionBuilder addConstructorArgValue(Object value){

    this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(

                    this.constructorArgIndex++, value);

    return this;

  }



  /**

    * Add a reference to a named bean as a constructor arg.

    * @see #addConstructorArgValue(Object)

    */

  public BeanDefinitionBuilder addConstructorArgReference(String beanName){

    this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(

                    this.constructorArgIndex++, new RuntimeBeanReference(beanName));

    return this;

  }



  /**

    * Add the supplied property value under the given name.

    */

  public BeanDefinitionBuilder addPropertyValue(String name, Object value){

    this.beanDefinition.getPropertyValues().add(name, value);

    return this;

  }



  /**

    * Add a reference to the specified bean name under the property specified.

    * @param name the name of the property to add the reference to

    * @param beanName the name of the bean being referenced

    */

  public BeanDefinitionBuilder addPropertyReference(String name, String beanName){

    this.beanDefinition.getPropertyValues().add(name, new RuntimeBeanReference(beanName));

    return this;

  }



  /**

    * Set the init method for this definition.

    */

  public BeanDefinitionBuilder setInitMethodName(String methodName){

    this.beanDefinition.setInitMethodName(methodName);

    return this;

  }



  // Methods that can be used to construct BeanDefinition

  /**

    * Return the current BeanDefinition object in its raw (unvalidated) form.

    * @see #getBeanDefinition()

    */

  public AbstractBeanDefinition getRawBeanDefinition(){

    return this.beanDefinition;

  }



  /**

    * Validate and return the created BeanDefinition object.

    */

  public AbstractBeanDefinition getBeanDefinition(){

    this.beanDefinition.validate();

    return this.beanDefinition;

  }

}Copy the code

The factory method

The second member of the trio that creates the object pattern is the factory method design pattern. It is perfectly suited to using a dynamic environment as the Spring framework. In effect, this pattern allows initialization through a common static method object, called a factory method. In this concept, we need to define an interface to create objects. But creation is created by classes that use related objects. But before jumping into the Spring world, let’s do an example with Java code:

public class FactoryMethodTest{ @Test public void test(){ Meal fruit = Meal.valueOf("banana"); Meal vegetable = Meal.valueOf("carrot"); assertTrue("Banana should be a fruit but is "+fruit.getType(), fruit.getType().equals("fruit")); assertTrue("Carrot should be a vegetable but is "+vegetable.getType(), vegetable.getType().equals("vegetable")); } } class Meal{ private String type; public Meal(String type){ this.type = type; } public String getType(){ return this.type; } // Example of factory method - different object is created depending on current context public static Meal valueOf(String ingredient){ if (ingredient.equals("banana")) { return new Meal("fruit"); } return new Meal("vegetable"); }}Copy the code

In Spring, we can create beans by specifying factory methods. This method is identical to the valueOf method seen in the previous code example. It is static and can take no or more arguments. To better understand the case, let’s look at an example. First, the configuration:

<bean id="welcomerBean" class="com.mysite.Welcomer" factory-method="createWelcomer"> <constructor-arg ref="messagesLocator"></constructor-arg> </bean> <bean id="messagesLocator" class="com.mysite.MessageLocator"> <property  name="messages" value="messages_file.properties"></property> </bean>Copy the code

Now focus on the initialization of this bean:

public class Welcomer{ private String message; public Welcomer(String message){ this.message = message; } public static Welcomer createWelcomer(MessageLocator messagesLocator){ Calendar cal = Calendar.getInstance(); String msgKey = "welcome.pm"; if (cal.get(Calendar.AM_PM) == Calendar.AM) { msgKey = "welcome.am"; } return new Welcomer(messagesLocator.getMessageByKey(msgKey)); }}Copy the code

When Spring constructs welcomerBean, it does so not through the traditional constructor, but through the defined static factory method createWelcomer. Also note that this method accepts some parameter (the instance of the MessageLocator bean contains all available messages) tags, which are usually reserved for traditional constructors.

The abstract factory

Finally, the abstract factory design pattern looks similar to the factory method. The difference is that we can think of abstract factories as factories in the industrial sense of the word, i.e. As something that provides the desired object. Factory components are: abstract factory, abstract product, product and customer. More precisely, an abstract factory defines the way objects are built. Abstract products are the result of this structure. A product is a concrete result of the same structure. A customer is a person who requires the creation of a product to abstract a factory. Again, before getting into the details of Spring, we’ll first illustrate the concept with sample Java code:

public class FactoryTest{



  // Test method which is the client

  @Test

  public void test(){

    Kitchen factory = new KitchenFactory();

    KitchenMeal meal = factory.getMeal("P.1");

    KitchenMeal dessert = factory.getDessert("I.1");

    assertTrue("Meal's name should be 'protein meal' and was '"+meal.getName()+"'", meal.getName().equals("protein meal"));

    assertTrue("Dessert's name should be 'ice-cream' and was '"+dessert.getName()+"'", dessert.getName().equals("ice-cream"));

  }



}



// abstract factory

abstract class Kitchen{

  public abstract KitchenMeal getMeal(String preferency);

  public abstract KitchenMeal getDessert(String preferency);

}



// concrete factory

class KitchenFactory extends Kitchen{

  @Override

  public KitchenMeal getMeal(String preferency){

    if (preferency.equals("F.1")) {

      return new FastFoodMeal();

    } else if (preferency.equals("P.1")) {

      return new ProteinMeal();

    }

    return new VegetarianMeal();

  }



  @Override

  public KitchenMeal getDessert(String preferency){

    if (preferency.equals("I.1")) {

      return new IceCreamMeal();

    }

    return null;

  }

}



// abstract product

abstract class KitchenMeal{

  public abstract String getName();

}



// concrete products

class ProteinMeal extends KitchenMeal{

  @Override

  public String getName(){

    return "protein meal";

  }

}



class VegetarianMeal extends KitchenMeal{

  @Override

  public String getName(){

    return "vegetarian meal";

  }

}



class FastFoodMeal extends KitchenMeal{

  @Override

  public String getName(){

    return "fast-food meal";

  }

}



class IceCreamMeal extends KitchenMeal{

  @Override

  public String getName(){

    return "ice-cream";

  }

}Copy the code

As we can see in this example, the abstract factory encapsulates the creation of the object. Object creation can use the same factory method pattern used for classical constructors. In Spring, the example of the factory is org. Springframework. Beans. Factory. The BeanFactory. With its implementation, we can access beans from Spring’s container. Depending on the strategy adopted, the getBean method can return the created object (shared instance, singleton scope) or initialize a new object (stereotype scope). In the implementation of BeanFactory, we can distinguish between: ClassPathXmlApplicationContext XmlWebApplicationContext, StaticWebApplicationContext StaticPortletApplicationContext, GenericApplicationContext StaticApplicationContext.

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"file:test-context.xml"}) public class TestProduct{ @Autowired private BeanFactory factory; @Test public void test(){ System.out.println("Concrete factory is: "+factory.getClass()); assertTrue("Factory can't be null", factory ! = null); ShoppingCart cart = (ShoppingCart) factory.getBean("shoppingCart"); assertTrue("Shopping cart object can't be null", cart ! = null); System.out.println("Found shopping cart bean:"+cart.getClass()); }}Copy the code

In this case, the abstract factory is represented by the BeanFactory interface. Specific factory is the first System. The out of print, is org. Springframework. Beans. Factory. Support. DefaultListableBeanFactory instance. Its abstraction is an object. In our example, the concrete product is an abstract product (Object) that has been forcefully converted to a ShoppingCart instance. The first article introduces us to a good programming style that is properly organized through design patterns. Here, we can see the use of the interpreter, builder, factory method, and factory in the Spring framework. The first is to help interpret text expressed in SpEL. The last three patterns are among the three musketeers who create design patterns, and their primary purpose in Spring is to simplify object creation. They create objects by breaking down initialization of complex objects (builders) or by concentrating initialization on common points (what else is called a factory, there must be common points).