Common design patterns in Java framework

Keywords: JDK Java Spring Attribute

Article directory

Preface

Many design patterns are used in Java framework, including agent pattern, responsibility chain pattern, observer pattern, common factory pattern, abstract factory pattern and builder pattern. Let's take a look at them.

1. What is design pattern

Design pattern represents the best practice and is usually adopted by experienced object-oriented software developers. Design pattern is a solution to the general problems faced by software developers in the process of software development. These solutions are summed up by many software developers after a long period of trial and error.

2. Java reflection technology

Java reflection technology is widely used. It can configure the fully qualified names, methods and parameters of classes, complete the initialization of objects, and enhance the configurability of Java. The basic principle of the vast number framework is also based on this technology.

Let's briefly understand the application of reflection:

2.1 building objects by reflection

(1) The object is constructed by nonparametric construction, and the code is as follows:

public class ReflectServiceImpl {
    public void sayHello(String name) {
        System.err.println("Hello " + name);
    }

    public ReflectServiceImpl getInstance(){
        ReflectServiceImpl object =null;
        try {
            //Generate objects by reflection
            object= (ReflectServiceImpl) Class.forName("com.ssm.learn.chapter2.reflect.ReflectServiceImpl").newInstance();
            
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return object;
    }
}

(2) The object is constructed by means of parameter construction, and the code is as follows:

public class ReflectServiceImpl2 {

    private String name;

    public ReflectServiceImpl2(String name) {
        this.name = name;
    }

    public void sayHello(String name) {
        System.err.println("Hello " + name);
    }

    public ReflectServiceImpl2 getInstance(){
        ReflectServiceImpl2 object =null;
        try {
             //Generate objects by reflection
            object= (ReflectServiceImpl2) Class.forName("com.ssm.learn.chapter2.reflect.ReflectServiceImpl2")
                    .getConstructor(String.class)
                    .newInstance("Zhang San");
            
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return object;
    }
}

  • The advantage of reflection: as long as the configuration can generate objects, it can decouple the program.

  • Drawback of reflection: slow operation.

Spring IoC is worth using reflection for flexibility and coupling reduction in most cases.

2.2 reflection method

The code is as follows:

public Object reflectMethod() {
        Object returnObj = null;
        ReflectServiceImpl target = new ReflectServiceImpl();
        try {
            //Method method = ReflectServiceImpl.class.getMethod("sayHello", String.class);
            
            //When there is a specific object target, but you don't know which class it is, you can write like this
            Method method = target.getClass().getMethod("sayHello", String.class);
            //Call method, equivalent to target.sayHello("Zhang San")
            returnObj = method.invoke(target, "Zhang San");
            
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return returnObj;
    }

2.3. Example

The code is as follows:

public static Object reflect() {
    ReflectServiceImpl object = null;
    try {
        object = (ReflectServiceImpl) Class.forName("com.ssm.learn.chapter2.reflect.ReflectServiceImpl")
                .newInstance();
        Method method = object.getClass().getMethod("sayHello", String.class);
        method.invoke(object,"Zhang San");
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return object;
}

public static void main(String[] args) {
    ReflectServiceImpl.reflect();
}

Run the program and get the following results:

Hello Zhang San

3. Dynamic agent mode

The significance of dynamic proxy is to generate a placeholder (also known as proxy object) to proxy real objects, so as to control the access of real objects.

For example: when customers come to a software company to talk about their needs, they don't directly talk to software engineers, but to find business. Customers think that business represents the company. As shown in the figure below:


Role of agent: add corresponding logic before or after real object access, or control whether to use real object according to other rules.

The agent is divided into two steps:

  1. Establishing agent relationship between agent object and real object

  2. The method of agent logic to realize agent object

The most commonly used dynamic proxy technologies in Java are:

  • JDK dynamic agent. The JDK has its own functions and must use interfaces, which is quite complex

  • CGLIB. The technology provided by the third party does not need to use the interface, which is relatively simple

3.1. JDK dynamic agent

First, define the HelloWorld interface. The code is as follows:

public interface HelloWorld{
    public void sayHelloWorld();
}

Then the implementation class HelloWorldImpl is provided to implement the interface. The code is as follows:

public class HelloWorldImpl implements HelloWorld{
    @Override
    public void sayHelloWorld(){
        System.out.println("Hello World");
    }
}

Dynamic agent binding and agent logic implementation are as follows:

public class JdkProxyExample implements InvocationHandler {

    //Real object
    private Object target = null;

    /**
     * Establish the proxy relationship between the proxy object and the real object
     *
     * @param target Real object
     * @return Surrogate object
     */
    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    /**
     * Agent method logic
     * @param proxy Surrogate object
     * @param method Current scheduling method
     * @param args Current method parameters
     * @return Proxy result return
     * @throws Throwable abnormal
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Enter agent logic method");
        System.out.println("Services before calling real objects");
        Object obj = method.invoke(target, args);//Equivalent to calling sayHelloWord method
        System.out.println("Service after calling real object");
        return obj;
    }
}

To test the JDK dynamic agent, the code is as follows:

public class TestProxy {

    @Test
    public void testJdkProxy() {
        JdkProxyExample jdkProxy = new JdkProxyExample();
        //Binding relationship, because it is hung under the interface HelloWorld, declare the proxy object HelloWorld proxy
        HelloWorld proxy = (HelloWorld) jdkProxy.bind(new HelloWorldImpl());
        //Note that at this time, the proxy object is already a proxy object, and it will enter the logical method invoke of the proxy
        proxy.sayHelloWorld();
    }
}

The operation results are as follows:

Enter agent logic method
 Services before scheduling real objects
Hello World
 Service after calling real object

3.2 CGLIB dynamic agent

The code is as follows:

public class CglibProxyExample implements MethodInterceptor {

    /**
     * Generate CGLIB proxy object
     * @param clazz Class class
     * @return Class CGLIB object of class
     */
    public Object getProxy(Class clazz) {
        //CGLIB enhancer enhancement class object
        Enhancer enhancer = new Enhancer();
        //Set enhancement type
        enhancer.setSuperclass(clazz);
        //Defining the proxy logical object as the current object requires the current object to implement the MethodInterceptor method
        enhancer.setCallback(this);
        //Generate and return proxy objects
        return enhancer.create();
    }

    /**
     * Agent logic method
     * @param proxy Surrogate object
     * @param method Execution method
     * @param args Method parameter
     * @param methodProxy Method agent
     * @return Agent logic return
     * @throws Throwable abnormal
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before calling a real object");
        Object result = methodProxy.invokeSuper(proxy, args);
        System.out.println("After calling the real object");
        return result;
    }
}

To test the CGLIB dynamic agent, the code is as follows:

public class TestProxy {

    @Test
    public void testCGLIBProxy(){
        CglibProxyExample cglibProxyExample = new CglibProxyExample();
        ReflectServiceImpl obj = (ReflectServiceImpl) cglibProxyExample.getProxy(ReflectServiceImpl.class);
        obj.sayHello("Zhang San");
    }
}

The test results are as follows:

Before calling a real object
 Hello Zhang San
 After calling the real object

3.3 interceptor

Because dynamic agent is generally difficult to understand, program developers will design an interceptor interface for developers to use. Developers only need to know the method, meaning and function of the interceptor interface, and do not need to know how dynamic agent is implemented.

3.4. Example

Use JDK dynamic agent to implement the logic of an Interceptor. First, define the Interceptor interface Interceptor. The code is as follows:

public interface Interceptor {
    /**
     * Call before real object
     * @param proxy Surrogate object
     * @param target Real object
     * @param method Calling method
     * @param args Method parameter
     * @return When true is returned, the method of the real object is reflected; when false is returned, the around method is called
     * When the real object method or around method is returned for execution, the after method is called
     */
    public boolean before(Object proxy, Object target, Method method,Object[] args);

    public void around(Object proxy, Object target, Method method,Object[] args);

    public void after(Object proxy, Object target, Method method,Object[] args);
}

To implement this interface, the code is as follows:

public class MyInterceptor implements Interceptor{
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("Logic before reflection method");
        return false;//The original method of not reflecting the proxy object
    }

    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("Logic after reflection method");
    }

    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("Replaces the method of the represented object");
    }
}

Use the interceptor in the JDK dynamic agent. The code is as follows:

public class InterceptorJdkProxy implements InvocationHandler {
    //Real object
    private Object target = null;
    //Full name of interceptor
    private String interceptorClass = null;

    public InterceptorJdkProxy(Object target, String interceptorClass) {
        this.target = target;
        this.interceptorClass = interceptorClass;
    }


    /**
     * Bind the delegate object and return a [proxy occupation]
     *
     * @param target Real object
     * @return Proxy object
     */
    public static Object bind(Object target, String InterceptorClass) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InterceptorJdkProxy(target, InterceptorClass));
    }

    /**
     * Call the method through the proxy object, and enter the method first
     *
     * @param proxy  Surrogate object
     * @param method Called method
     * @param args   Method parameter
     * @return Agent result return
     * @throws Throwable abnormal
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (interceptorClass == null) {
            //No interceptor is set to reflect the original method directly
            return method.invoke(target, args);
        }
        Object result = null;
        //Generate interceptor by reflection
        Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
        //Call pre method
        if (interceptor.before(proxy, target, method, args)) {
            //Return true to reflect the original object method
            result = method.invoke(target, args);
        } else {
            //Return false to execute around method
            interceptor.around(proxy, target, method, args);
        }
        //Call Post method
        interceptor.after(proxy, target, method, args);
        return result;
    }
}

Code execution steps:

  1. In the bind method, an object is bound with a JDK dynamic proxy, and then the proxy object is returned.
  2. If the interceptor is not set, the method that reflects the real object directly, and then ends. Otherwise, go to step three.
  3. Generate the interceptor by reflection and prepare to use it.
  4. Call the before method of the interceptor, if it returns true, the original method will be reflected; otherwise, run the around method of the interceptor.
  5. after method of calling interceptor
  6. Return result

Test the interceptor with the following code:

public class TestInterceptor {

    @Test
    public void testInterceptor(){
       HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),"com.ssm.learn.chapter2.interceptor.MyInterceptor");
       proxy.sayHelloWorld();
    }
}

The test results are as follows:

Logic before reflection method
 Logic after reflection method
 Replaces the method of the represented object

4. Responsibility chain model

For example, a programmer needs a week off. If the leave application form is regarded as an object, it needs to be approved by project manager, Department Manager, personnel manager and other roles. Each role has the opportunity to approve or modify the application form by blocking it. At this time, we need to consider providing the processing logic of project manager, Department Manager and personnel manager, so we need to provide three interceptors, and pass the leave application form. The leave example is shown in the figure:
When an object is intercepted by multiple interceptors in a chain (interceptors can also not intercept), we call such a design pattern responsibility chain pattern, which is used for scenes where an object passes through multiple roles.

Back to the previous example, when the application form comes to the project manager, the manager may change the application time from "one week" to "five days", thus affecting the subsequent approval, because the latter approval will be based on the previous results. At this time, consider using layer by layer agent, that is, when the application form (target) comes to the project manager, use the first dynamic agent proxy1. When it comes to the Department Manager, the Department Manager will get a second dynamic agent proxy2 generated on the basis of proxy1 of the project manager to handle the logic of the Department Manager, and so on.

The interception logic is as follows:

4.1. Example

Define three interceptors as follows:
public class Interceptor1 implements Interceptor{
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("[Interceptor 1] before Method");
        return true;
    }

    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {

    }

    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("[Interceptor 1] after Method");
    }
}
/************************************Interceptor 2*************************************/
public class Interceptor2 implements Interceptor{
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("[Interceptor 2] before Method");
        return true;
    }

    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {

    }

    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("[Interceptor 2] after Method");
    }
}
/************************************Interceptor 3*************************************/
public class Interceptor3 implements Interceptor{
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("[Interceptor 3] before Method");
        return true;
    }

    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {

    }

    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("[Interceptor 3] after Method");
    }
}

Test the responsibility chain mode, the code is as follows:

@Test
public void testInterceptors() {
    HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), "com.ssm.learn.chapter2.interceptor.Interceptor1");
    HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(proxy1, "com.ssm.learn.chapter2.interceptor.Interceptor2");
    HelloWorld proxy3 = (HelloWorld) InterceptorJdkProxy.bind(proxy2, "com.ssm.learn.chapter2.interceptor.Interceptor3");
    proxy3.sayHelloWorld();
}

The operation results are as follows:

[Interceptor 3] before Method
[Interceptor 2] before Method
[Interceptor 1] before Method
Hello World
[Interceptor 1] after Method
[Interceptor 2] after Method
[Interceptor 3] after Method

It can be seen that the advantage of the responsibility chain mode is that we can add new interceptors to the delivery chain and add intercepting logic. Its disadvantage is that it will increase proxy and reflection, while the performance of proxy and reflection is not high.

5. Observer mode

The observer pattern, also known as the publish and subscribe pattern, defines a one-to-many dependency relationship, which enables multiple observers to monitor the status of the observed at the same time. When the status of the observer changes, all observers will be notified and updated automatically.

Example 1: Micro blog push mechanism. When the author posts a new micro blog, all fans who pay attention to the author will receive a push.

Example 2: a merchant has some products. He cooperates with some e-commerce companies. Whenever there are new products, he will push them to e-commerce companies. Now he only cooperates with Taobao and Jingdong, so there is such a pseudo code:

If (there are new products in the product library){
	Push new products to Taobao;
	Push new products to Jingdong;
}

If the company signs cooperation agreements with Gome, Suning, Dangdang and vipshop, the pseudo code will be changed when necessary:

If (there are new products in the product library){
	Push new products to Taobao;
	Push new products to Jingdong;
	Push new products to Gome;
	Push new products to Suning;
	Push new products to Dangdang;
	Push new products to vipshop;
}

In this way, if there are other e-commerce cooperation, continue to add logic in the if statement. First of all, if there are more and more e-commerce, the logic of if statement will become more and more complex. In addition, if there is an exception in pushing goods to Taobao, you need to catch the exception to avoid affecting the subsequent e-commerce interface, which makes it unable to proceed further, so the code coupling will increase. Secondly, if statements stack too much code, which is not conducive to maintenance and extension.

**The observer model makes more use of expansion, and the responsibility is more clear. **First, each e-commerce interface is regarded as an observer, and each observer can observe the product list (monitored object). When the company releases a new product, it will be sent to this product list, and then the product list will change. At this time, each e-commerce interface (observer) can be triggered to send the new product to the corresponding cooperative e-commerce. An example of observer mode is shown in the figure:

Similarly, an object (e-commerce interface) will listen to another object (product list). When the monitored object (product list) changes, the object (e-commerce interface) will trigger certain behaviors to adapt to the changed logical mode, which we call observer mode.

The advantage of this is that there is no if statement in the program, and the observer will make corresponding behavior according to the change of the observed object. No matter Taobao, Jingdong or other e-commerce teams want to maintain their own logic without coupling together. At the same time, the responsibility is clear. The product team only needs to maintain the product list. The e-commerce team can add observers to monitor the e-commerce interface of the product.

5.1. Example

Observed - product list, inheriting the Observable class, the code is as follows:

public class ProductList extends Observable {
    //Product list
    private List<String> productList = null;
    //Unique instance of class
    private static ProductList instance;

    //Constructor privatization
    private ProductList() {
    }

    /**
     * Get unique instance
     *
     * @return Unique instance of product list
     */
    public static ProductList getInstance() {
        if (instance == null) {
            instance = new ProductList();
            instance.productList = new ArrayList<>();
        }
        return instance;
    }

    /**
     * Add observers (e-commerce interface)
     * @param observer Observer
     */
    public void addProductListObserver(Observer observer) {
        this.addObserver(observer);
    }

    /**
     * New product
     * @param newProduct new product
     */
    public void addProduct(String newProduct){
        productList.add(newProduct);
        System.out.println("New products added to product list "+newProduct);
        this.setChanged();//Set the observed object to change
        this.notifyObservers(newProduct);//Notify observers and deliver new products
    }
}

In this case, the construction method is used to be privatized to avoid creating objects through the new method. Instead, the getInstance() method is used to obtain a single instance of the product list. Here, the single instance mode is used.

Observer - Take Taobao and Jingdong as examples to implement their e-commerce interfaces. As observers, they need to implement the update method of the observer interface. The code is as follows:

public class TaoBaoObserver implements Observer {
    @Override
    public void update(Observable o, Object product) {
        String newProduct = (String) product;
        System.out.println("Send new product[" + newProduct + "]Synchronized to Taobao Mall");
    }
}
public class JingDongObserver implements Observer {
    @Override
    public void update(Observable o, Object product) {
        String newProduct = (String) product;
        System.out.println("Send new product[" + newProduct + "]Synchronous to Jingdong Mall");
    }
}

Test the observer mode with the following code:

ublic class TestObserver {
    @Test
    public void testObserver() {
        ProductList observable = ProductList.getInstance();
        TaoBaoObserver taoBaoObserver = new TaoBaoObserver();
        JingDongObserver jingDongObserver = new JingDongObserver();
        observable.addObserver(taoBaoObserver);
        observable.addObserver(jingDongObserver);
        observable.addProduct("New product 1");
    }
}

The operation results are as follows:

New products added to product list 1
 Send new product [new product 1] to Jingdong Mall synchronously
 Send new product [new product 1] to Taobao Mall synchronously

6. Factory pattern and abstract factory pattern

In most cases, we create objects in a new way. For example, there may be many kinds of cars in reality, including buses, cars, ambulances, off-road vehicles, trucks, etc. there are specific models under each kind. It is difficult to manage so many cars produced in a factory, so it is often necessary to further divide them into different factories: buses, cars, etc. But the customer doesn't need to know how to split the factory. He only tells the customer service what kind of car they need, and the customer service will find the corresponding factory to produce the car according to the customer's requirements. For the customer, the car factory is just an abstract concept, he just probably knows that there is such a factory to meet his needs.

6.1. Simple Factory mode:

For example, there is an IProduct product interface with five implementation classes, Product1, Product2, Product3, Product4, and Product5. They belong to a large class and can be managed through the product factory. However, due to different types, initialization is different. In order to use the ProductFactory class to create objects of these products, users can determine which products they need through the product number, as shown in the figure:

The pseudo code of ProductFactory is as follows:

public class ProductFactory{
    public static IProduct createProduct(String productNo){
        switch(productNo){
            case "1":return new Product1(XXX);
            case "2":return new Product2(XXX);
            case "3":return new Product3(XXX);
            case "4":return new Product4(XXX);
            case "5":return new Product5(XXX);
            default:
                throw new NotSupprotedException("Production of this number of products is not supported.");
        }
    }
}

For the program caller, he only needs to know that the corresponding product can be obtained by specifying the product number through the factory's createProduct method, and the product meets the specification of the interface IProduct, so initialization is much easier. For the creation of product objects, some specific product rules can be written into the factory class.

6.2. Abstract Factory mode

Abstract factory pattern can provide an interface for clients to create product objects in multiple product families without specifying specific products. Sometimes objects are very complex. There are dozens of objects, which are divided into several categories. If you use a simple factory, the logic of the factory will be too complex. Therefore, the factory is divided into several parts, so as to facilitate the maintenance of product rules. The abstract factory diagram is shown as follows:

In order to unify, an interface specification (IProductFactory) needs to be developed. All concrete factories and abstract factories need to implement this interface. The code is as follows:

public interface IProductFactory {
    public IProduct createProduct(String productNo);
}

Now we will implement three factory classes as follows:

public class ProductFactory1 implements IProductFactory {
    @Override
    public IProduct createProduct(String productNo) {
        IProduct product = XXX;//Factory 1 generates product object rules, which can be rules of a class of products
        return product;
    }
}
public class ProductFactory2 implements IProductFactory {
    @Override
    public IProduct createProduct(String productNo) {
        IProduct product = XXX;//Factory 2 generates product object rules, which can be rules of a class of products
        return product;
    }
}
public class ProductFactory3 implements IProductFactory {
    @Override
    public IProduct createProduct(String productNo) {
        IProduct product = XXX;//Factory 3 generates product object rules, which can be rules of a class of products
        return product;
    }
}

Using a public factory, it provides rules to select factories. We make the following business contract: create objects with factory ProductFactoryx with product number starting with x. The code is as follows:

public class ProductFactory implements IProductFactory {
    @Override
    public IProduct createProduct(String productNo) {
        char ch = productNo.charAt(0);
        IProductFactory factory = null;
        if (ch == '1') {
            factory = new ProductFactory1();
        } else if (ch == '2') {
            factory = new ProductFactory2();
        } else if (ch == '3') {
            factory = new ProductFactory3();
        }
        if (factory != null) {
            return factory.createProduct(productNo);
        }
        return null;
    }
}

For designers, ProductFactory is an abstract factory, so creating objects is much easier for callers. Each factory only needs to maintain the generation of its type product objects, and the specific factory rules will not be particularly complex and difficult to maintain.

7. Builder mode

The builder model can separate the internal representation (attribute) of a product from the production process of a product, so that a construction process can generate a product object with different internal representation.

For example, some travel packages can be divided into: ordinary adults, retired elderly people, half ticket children with seats, free children without seats, soldiers and their families, etc. they have different regulations and preferences. It is inconvenient to create objects through new or factory mode because of too many parameters and complex objects.

The Builder pattern is a pattern of building objects step by step. Each step is coordinated with a configuration class, and then all information is passed to the constructor to complete the construction object.

7.1. Example

Create a configuration class object TickerHelper, which can help us build objects step by step. The code is as follows:

public class TicketHelper {
    public void buildAdult(String info) {
        System.out.println("To construct the logic of adult ticket:" + info);
    }

    public void buildChildrenForSeat(String info) {
        System.out.println("Construct the logic of children's ticket with seats:" + info);
    }

    public void buildChildrenForNoSeat(String info) {
        System.out.println("To construct the logic of no seat child ticket:" + info);
    }

    public void buildElderly(String info) {
        System.out.println("To construct the logic of elderly ticket:" + info);
    }

    public void buildSoldier(String info) {
        System.out.println("To construct the logic of votes for soldiers and their families:" + info);
    }
}

Then, you need a construction class -- TicketBuilder, with the code as follows:

public class TicketBuilder {
    public static Object builder(TicketHelper helper){
        System.out.println("adopt TicketHelper Build package information");
        return null;
    }
}

Through these two classes, you can build a package ticket. The code is as follows:

public class TestBuilder {
    @Test
    public void testBuilder() {
        TicketHelper helper = new TicketHelper();
        helper.buildAdult("Adult ticket");
        helper.buildChildrenForSeat("There are children.");
        helper.buildChildrenForNoSeat("Children without seats");
        helper.buildElderly("Elderly vote");
        helper.buildSoldier("Military ticket");
        Object ticket = TicketBuilder.builder(helper);
    }
}

This paper refers to Yang Kaizhen's "Java EE Internet lightweight framework integration development"

Published 5 original articles, won praise 2, visited 1121
Private letter follow

Posted by rickaclark on Fri, 21 Feb 2020 20:55:30 -0800