Cainiao (II) -- use Java generic construction template method mode, java Template

Source: Internet
Author: User

Cainiao (II) -- use Java generic construction template method mode, java Template

If you find that you have a lot of repeated code, you may consider using the template method to eliminate the error-prone duplicate code. Here is an example: the two classes below complete almost identical functions:


As you can see, only the comments are different. All other steps are the same.


ProductCsvReader. java

Public class ProductCsvReader {Set <Product> getAll (File file) throws IOException {Set <Product> returnSet = new HashSet <> (); try (BufferedReader reader = new BufferedReader (new FileReader (file) {String line = reader. readLine (); while (line! = Null &&! Line. trim (). equals ("") {String [] tokens = line. split ("\ s *, \ s *"); // different Product products = new product (Integer. parseInt (tokens [0]), tokens [1], new BigDecimal (tokens [2]); returnSet. add (product); line = reader. readLine () ;}} return returnSet ;}}

CustomerCsvReader. java
Public class CustomerCsvReader {Set <Customer> getAll (File file) throws IOException {Set <Customer> returnSet = new HashSet <> (); try (BufferedReader reader = new BufferedReader (new FileReader (file) {String line = reader. readLine (); while (line! = Null &&! Line. trim (). equals ("") {String [] tokens = line. split ("\ s *, \ s *"); // different Customer customer = new Customer (Integer. parseInt (tokens [0]), tokens [1], tokens [2], tokens [3]); returnSet. add (customer); line = reader. readLine () ;}} return returnSet ;}}

In this example, there are only two entities, but a real system may have dozens of entities, so there are a lot of repetitive and error-prone code. You may find that the Dao layer has the same situation. Each Dao performs addition, deletion, modification, and query operations in almost the same way. The only difference is the entity and table. Let's refactor these annoying codes. According to one of the principles mentioned in Part 1 of the GoF design model, we should "encapsulate different concepts". The difference between ProductCsvReader and CustomerCsvReader is that there are annotated codes. So what we need to do is to put the same class into one class and extract different classes to another class. Let's first write ProductCsvReader. We use the Extract Method to Extract the annotated part:


ProductCsvReader. java after Extract Method
public class ProductCsvReader {     Set<Product> getAll(File file) throws IOException {        Set<Product> returnSet = new HashSet<>();        try (BufferedReader reader = new BufferedReader(new FileReader(file))){            String line = reader.readLine();            while (line != null && !line.trim().equals("")) {                String[] tokens = line.split("\\s*,\\s*");                Product product = unmarshall(tokens);                returnSet.add(product);                line = reader.readLine();            }        }        return returnSet;    }    Product unmarshall(String[] tokens) {        Product product = new Product(Integer.parseInt(tokens[0]), tokens[1],                 new BigDecimal(tokens[2]));        return product;    }}

Now we have separated the same (repeated) code from the different (unique) code. We want to create a parent class named AbstractCsvReader, which includes two classes: ProductReader and CustomerReader) the same part. We define it as an abstract class because we do not need to instantiate it. Then we will use the Pull Up Method to reconstruct the parent class.


AbstractCsvReader. java
abstract class AbstractCsvReader {    Set<Product> getAll(File file) throws IOException {        Set<Product> returnSet = new HashSet<>();        try (BufferedReader reader = new BufferedReader(new FileReader(file))){            String line = reader.readLine();            while (line != null && !line.trim().equals("")) {                String[] tokens = line.split("\\s*,\\s*");                Product product = unmarshall(tokens);                returnSet.add(product);                line = reader.readLine();            }        }        return returnSet;    }}

ProductCsvReader. java after Pull Up Method
public class ProductCsvReader extends AbstractCsvReader {    Product unmarshall(String[] tokens) {       Product product = new Product(Integer.parseInt(tokens[0]), tokens[1],                 new BigDecimal(tokens[2]));        return product;    }}

If the subclass does not have the 'unmarshall 'method, the class cannot be compiled (it calls the unmarshall method), so we need to create an abstract method called unmarshall.


AbstractCsvReader. java with abstract unmarshall method
abstract class AbstractCsvReader {    Set<Product> getAll(File file) throws IOException {        Set<Product> returnSet = new HashSet<>();        try (BufferedReader reader = new BufferedReader(new FileReader(file))){            String line = reader.readLine();            while (line != null && !line.trim().equals("")) {                String[] tokens = line.split("\\s*,\\s*");                Product product = unmarshall(tokens);                returnSet.add(product);                line = reader.readLine();            }        }        return returnSet;    }    abstract Product unmarshall(String[] tokens);}

At this point, AbstractCsvReader is the parent class of ProductCsvReader, but not the parent class of CustomerCsvReader. If CustomerCsvReader inherits AbstractCsvReader, an error is returned. To solve this problem, we use generics.


AbstractCsvReader. java with Generics
abstract class AbstractCsvReader<T> {    Set<T> getAll(File file) throws IOException {        Set<T> returnSet = new HashSet<>();        try (BufferedReader reader = new BufferedReader(new FileReader(file))){            String line = reader.readLine();            while (line != null && !line.trim().equals("")) {                String[] tokens = line.split("\\s*,\\s*");                T element = unmarshall(tokens);                returnSet.add(product);                line = reader.readLine();            }        }        return returnSet;    }    abstract T unmarshall(String[] tokens);}

ProductCsvReader. java with Generics
public class ProductCsvReader extends AbstractCsvReader<Product> {    @Override    Product unmarshall(String[] tokens) {       Product product = new Product(Integer.parseInt(tokens[0]), tokens[1],                 new BigDecimal(tokens[2]));        return product;    }}

CustomerCsvReader. java with Generics
public class CustomerCsvReader extends AbstractCsvReader<Customer> {    @Override    Customer unmarshall(String[] tokens) {        Customer customer = new Customer(Integer.parseInt(tokens[0]), tokens[1],                 tokens[2], tokens[3]);        return customer;    }}

This is what we want! There are no repeated code! The method in the parent class is "template", which contains the unchanged code. The changed things are implemented as abstract methods in sub-classes. Remember, when you refactor, You should have automated unit tests to ensure that you do not destroy your code. I am using JUnit. You can use the code I post here, or find some examples of other design patterns in this Github library. Before the end, I would like to explain the shortcomings of the template method. The template method depends on inheritance and has the Fragile Base Class Problem. Simply put, modifying a parent class will have unexpected adverse effects on its subclass. In fact, the GoF design model, one of the basic design principles, advocates "Multi-Purpose Combination with less inheritance", and many other design patterns also tell you how to avoid code duplication, at the same time, the complex or error-prone code should be inherited with as few dependencies as possible. Welcome to the discussion so that I can improve the quality of my blog.


Original address;Template Method Pattern Example Using Java Generics


Translation is not good. Thank you!




Java generic set application and Method

Define a generic class
Import java. util .*;
/**
* Description:
* <Br/> Copyright (C), 2005-2008, Yeeku. H. Lee
* <Br/> This program is protected by copyright laws.
* <Br/> Program Name:
* <Br/> Date:
* @ Author Yeeku. H. Lee kongyeeku@163.com
* @ Version 1.0
*/
// The generic declaration is used to define the Apple category.
Public class Apple <T>
{
// Use a T-type parameter to define attributes
Private T info;

Public Apple (){}
// Use the T-type parameter to define the method in the following method:
Public Apple (T info)
{
This.info = info;
}
Public void setInfo (T info)
{
This.info = info;
}
Public T getInfo ()
{
Return this.info;
}
Public static void main (String [] args)
{
// Because the actual String type is passed to the T-shaped parameter, the constructor parameter can only be String
Apple <String> a1 = new Apple <String> ("Apple ");
System. out. println (a1.getInfo ());
// Because the actual type of the parameter passed to the T-shaped parameter is Double, the constructor parameter can only be Double or double.
Apple <Double> a2 = new Apple <Double> (5.67 );
System. out. println (a2.getInfo ());
}
}

The role of generics:
For example, in the List collection class, List can be put into various types of data. How can we let the system know what type of data is stored in List? In this case, you need to use a generic type, such as List <String> listString = new ArrayList <String> (); in this way, you can specify that listString stores String-type data.

There are a lot of generic content. I recommend Li Gang's crazy java handout for a book. I also use it to learn it myself.

How to Use generics in the return type in java Methods

This is not the case!
List <Integer> and List <String> are different return types!
You can return List <Object>, but cast is required later!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.