Beginner's translation (ii)--using Java Generic construction template method pattern

Source: Internet
Author: User

If you find that you have a lot of duplicated code, you might consider using a template method to eliminate error-prone duplicate code. Here's an example: The following two classes complete almost the same functionality:

    1. Instantiate and initialize a reader to read the CSV file;
    2. Read each line and parse;
    3. Fills the characters of each line into the product or Customer object;
    4. Add each object to the set;
    5. Returns the set.


As you can see, only the annotated place is different. All other steps are the same.

Productcsvreader.java
 Public classProductcsvreader {Set<Product> getAll (file file)throwsIOException {Set<Product> Returnset =NewHashset<>(); Try(BufferedReader reader =NewBufferedReader (Newfilereader (file))) {String Line=Reader.readline ();  while(Line! =NULL&&!line.trim (). Equals ("") ) {string[] tokens= Line.split ("\\s*,\\s*"); //differentProduct Product =NewProduct (Integer.parseint (Tokens[0]), tokens[1],NewBigDecimal (tokens[2]));                Returnset.add (product); Line=Reader.readline (); }        }        returnReturnset; }}

Customercsvreader.java
 Public classCustomercsvreader {Set<Customer> getAll (file file)throwsIOException {Set<Customer> Returnset =NewHashset<>(); Try(BufferedReader reader =NewBufferedReader (Newfilereader (file))) {String Line=Reader.readline ();  while(Line! =NULL&&!line.trim (). Equals ("") ) {string[] tokens= Line.split ("\\s*,\\s*"); //differentCustomer customer =NewCustomer (Integer.parseint (Tokens[0]), tokens[1], tokens[2], tokens[3]);                Returnset.add (customer); Line=Reader.readline (); }        }        returnReturnset; }}

for 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, and that each DAO is almost the same operation when it is being checked for deletions, and the only difference is the entity and the table. Let's refactor the annoying code. According to one of the principles mentioned in the first part of the GOF design pattern, we should "encapsulate different concepts" between Productcsvreader and Customercsvreader, unlike annotated code. So what we're going to do is put the same into one class, different to the other. We start by writing Productcsvreader, and we use Extract method to extract the annotated part:

Productcsvreader.java after Extract Method
 Public classProductcsvreader {Set<Product> getAll (file file)throwsIOException {Set<Product> Returnset =NewHashset<>(); Try(BufferedReader reader =NewBufferedReader (Newfilereader (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 (); }        }        returnReturnset; } product Unmarshall (string[] tokens) {Product Product=NewProduct (Integer.parseint (Tokens[0]), tokens[1],                 NewBigDecimal (tokens[2])); returnproduct; }}

now that we've separated the same (duplicated) code from the different (unique) code, we're going to create a parent class Abstractcsvreader, It includes the same parts as two classes (Productreader and Customerreader). We define it as an abstract class, because we don't need to instantiate it. We will then use the pull-up method to refactor the parent class.

Abstractcsvreader.java
Abstract classAbstractcsvreader {Set<Product> getAll (file file)throwsIOException {Set<Product> Returnset =NewHashset<>(); Try(BufferedReader reader =NewBufferedReader (Newfilereader (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 (); }        }        returnReturnset; }}

Productcsvreader.java after pull up Method
 Public class extends Abstractcsvreader {    product unmarshall (string[] tokens) {       new product (Integer.parseint ( Tokens[0]), tokens[1],                 new BigDecimal (tokens[2]);         return product;    }}

if there is no ' unmarshall ' method in the subclass, the class cannot compile (it calls the Unmarshall method), so we will create an abstract method called Unmarshall .

Abstractcsvreader.java with abstract Unmarshall method
Abstract classAbstractcsvreader {Set<Product> getAll (file file)throwsIOException {Set<Product> Returnset =NewHashset<>(); Try(BufferedReader reader =NewBufferedReader (Newfilereader (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 (); }        }        returnReturnset; }    AbstractProduct unmarshall (string[] tokens);}

now, at this point, Abstractcsvreader is the parent class of Productcsvreader, but not the parent class of Customercsvreader. If Customercsvreader inherits Abstractcsvreader compilation will error. To solve this problem we use generics.

Abstractcsvreader.java with generics
Abstract classAbstractcsvreader<t>{Set<T> getAll (file file)throwsIOException {Set<T> Returnset =NewHashset<>(); Try(BufferedReader reader =NewBufferedReader (Newfilereader (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 (); }        }        returnReturnset; }    AbstractT unmarshall (string[] tokens);}

Productcsvreader.java with generics
 Public class extends Abstractcsvreader<product> {    @Override    Product unmarshall (string[] tokens) {       new Product (Integer.parseint (Tokens[0]), tokens[1],                 new BigDecimal (tokens[2]));         return  product;}    }

Customercsvreader.java with generics
 Public class extends Abstractcsvreader<customer> {    @Override    Customer unmarshall (string[] tokens) {        new Customer (Integer.parseint (Tokens[0]), tokens[1],                 tokens[2], tokens[3]);         return customer;    }}

That's what we want! No more duplicate code! The method in the parent class is "template", which contains the immutable code. Those things that change are implemented as abstract methods in subclasses. Remember, when you refactor, you should have automated unit tests to ensure that you don't break your code. I use JUnit, you can use the code I post here, or you can find some examples of other design patterns in this GitHub library . Before I finish, I want to talk about the drawbacks of the template approach. The template method relies on inheritance and suffers from the fragile Base Class problem. Simply put, modifying a parent class can have unintended undesirable effects on the subclass that inherits it. In fact, one of the basic design principles of the GOF design pattern advocates "multi-use combination less inheritance", and many other design patterns also tell you how to avoid code duplication while allowing complex or error-prone code to rely on inheritance as little as possible. Welcome to exchange so that I can improve the quality of my blog.


The original address;Template Method Pattern Example Using Java generics


The translation is not good, welcome to shoot Bricks!



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.