Refactoring Design Pattern với tính năng mới trong Java 8

Trong bài này, tôi sẽ giới thiệu với các bạn cách sử dụng một số tính năng mới trong Java 8 như Lambda FunctionSupplier, … để refactor code của một số Design Pattern.

1. Refactoring Strategy Design Pattern

1.1. Strategy Pattern là gì?

Các bạn xem lại bài viết “Hướng dẫn Java Design Pattern – Strategy“.

1.2. Ví dụ Strategy Pattern

Strategy.java

package com.maixuanviet.designpatterns.strategy;
 
public interface Strategy {
    void performTask();
}

1.2.1. Strategy Pattern không sử dụng Lambda

StartegyPatternExample.java

package com.maixuanviet.designpatterns.strategy;
 
import java.util.Arrays;
import java.util.List;
 
class EagerStrategy implements Strategy {
 
    @Override
    public void performTask() {
        System.out.println("Eager strategy");
    }
}
 
class LazyStratgey implements Strategy {
 
    @Override
    public void performTask() {
        System.out.println("Lazy strategy");
    }
}
 
public class StartegyPatternExample {
    public static void main(String[] args) {
        Strategy eagerStrategy = new EagerStrategy();
        Strategy lazyStrategy = new LazyStratgey();
        List<Strategy> strategies = Arrays.asList(eagerStrategy, lazyStrategy);
        for (Strategy stg : strategies) {
            stg.performTask();
        }
    }
}

1.2.2. Strategy Pattern sử dụng Lambda

package com.maixuanviet.designpatterns.strategy;
 
import java.util.Arrays;
import java.util.List;
 
public class LambdaStartegyPatternExample {
 
    public static void main(String[] args) {
        Strategy eagerStrategy = () -> System.out.println("Eager strategy");
        Strategy lazyStrategy = () -> System.out.println("Lazy strategy");
        List<Strategy> strategies = Arrays.asList(eagerStrategy, lazyStrategy);
        strategies.forEach((elem) -> elem.performTask());
    }
}

Như bạn thấy, sử dụng Lambda code chúng ta đơn giản hơn nhiều, không cần tạo thêm các class.

2. Refactoring Observer Design Pattern

2.1. Observer Pattern là gì?

Các bạn xem lại bài viết “Hướng dẫn Java Design Pattern – Observer“.

2.2. Ví dụ Observer Pattern

Observer.java

package com.maixuanviet.designpatterns.observer;
 
public interface Observer {
    void update(String str);
}

Subject.java

package com.maixuanviet.designpatterns.observer;
 
public interface Subject {
 
    void registerObserver(Observer observer);
 
    void notifyObservers(String str);
}

AccountService.java

package com.maixuanviet.designpatterns.observer;
 
import java.util.ArrayList;
import java.util.List;
 
public class AccountService implements Subject {
 
    private final List<Observer> observers = new ArrayList<>();
 
    public void login(String username) {
        System.out.println("Login: " + username);
        notifyObservers(username);
    }
 
    @Override
    public void registerObserver(Observer observer) {
        if (!observers.contains(observer)) {
            observers.add(observer);
        }
    }
 
    @Override
    public void notifyObservers(String str) {
        for (Observer observer : observers) {
            observer.update(str);
        }
    }
}

2.2.1. Observer Pattern không sử dụng Lambda

package com.maixuanviet.designpatterns.observer;
 
class Logger implements Observer {
    @Override
    public void update(String str) {
        System.out.println("Logger: " + str);
    }
}
 
class Mailer implements Observer {
    @Override
    public void update(String str) {
        System.out.println("Mailer: " + str);
    }
}
 
public class ObserverPatternExample {
    public static void main(String[] args) {
        AccountService account = new AccountService();
        // Register Observers
        account.registerObserver(new Logger());
        account.registerObserver(new Mailer());
        // Call service
        account.login("maixuanviet");
    }
}

2.2.2. Observer Pattern sử dụng Lambda

package com.maixuanviet.designpatterns.observer;
 
public class LambdaObserverPatternExample {
    public static void main(String[] args) {
        AccountService account = new AccountService();
        // Register Observers
        account.registerObserver(str -> System.out.println("Logger: " + str));
        account.registerObserver(str -> System.out.println("Mailer: " + str));
        // Call service
        account.login("maixuanviet");
    }
}

Chạy 2 chương trình trên, ta có cùng kết quả:

Login: maixuanviet
Logger: maixuanviet
Mailer: maixuanviet

3. Refactoring Chain of Responsibility Pattern

3.1. Chain of Responsibility Pattern là gì?

Các bạn xem lại bài viết “Hướng dẫn Java Design Pattern – Chain of Responsibility“.

3.2. Ví dụ Chain of Responsibility Pattern

Filter.java

package com.maixuanviet.designpatterns.chain;
 
public abstract class Filter {
 
    private Filter nextFilter;
 
    public String doFilter(String str) {
        String result = handleString(str);
        if (nextFilter != null) {
            return nextFilter.doFilter(result);
        }
        return result;
    }
 
    public void setNextFilter(Filter nextFilter) {
        this.nextFilter = nextFilter;
    }
 
    protected abstract String handleString(String str);
}

3.2.1. Chain of Responsibility Pattern không sử dụng Lambda

package com.maixuanviet.designpatterns.chain;
 
class Filter1 extends Filter {
    @Override
    protected String handleString(String str) {
        System.out.println("Filter1: " + str);
        return str + "->Filter1";
    }
}
 
class Filter2 extends Filter {
    @Override
    protected String handleString(String str) {
        System.out.println("Filter2: " + str);
        return str + "->Filter2";
    }
}
 
class Filter3 extends Filter {
    @Override
    protected String handleString(String str) {
        System.out.println("Filter3: " + str);
        return str + "->Filter3";
    }
}
 
class AppFilter {
    public static Filter getFilter() {
        Filter1 filter1 = new Filter1();
        Filter2 filter2 = new Filter2();
        Filter3 filter3 = new Filter3();
        filter1.setNextFilter(filter2);
        filter2.setNextFilter(filter3);
        return filter1;
    }
}
 
public class ChainOfResponsibilityExample {
 
    public static void main(String[] args) {
        // Build the chain of responsibility
        Filter filter = AppFilter.getFilter();
        // Execute filter
        String result = filter.doFilter("maixuanviet");
        System.out.println("Final data: " + result);
    }
}

3.2.2. Chain of Responsibility Pattern sử dụng Lambda và Function

package com.maixuanviet.designpatterns.chain;
 
import java.util.function.Function;
import java.util.function.UnaryOperator;
 
public class LamdaChainOfResponsibilityExample {
 
    public static void main(String[] args) {
 
        UnaryOperator<String> filter1 = (str) -> {
            System.out.println("Filter1: " + str);
            return str + "->Filter1";
        };
 
        UnaryOperator<String> filter2 = (str) -> {
            System.out.println("Filter2: " + str);
            return str + "->Filter2";
        };
 
        UnaryOperator<String> filter3 = (str) -> {
            System.out.println("Filter3: " + str);
            return str + "->Filter3";
        };
 
        // Compose all functions resulting in a chain of operations.
        Function<String, String> appFilter = filter1.andThen(filter2).andThen(filter3);
        String result = appFilter.apply("maixuanviet");
        System.out.println("Final data: " + result);
    }
}

Lưu ý: UnaryOperator là một Function, có cùng kiểu dữ liệu đầu vào và đầu ra. UnaryOperator<String> tương đương với cách viết Function<String, String>.

Chạy 2 chương trình trên, chúng ta có cùng kết quả:

Filter1: maixuanviet
Filter2: maixuanviet->Filter1
Filter3: maixuanviet->Filter1->Filter2
Final data: maixuanviet->Filter1->Filter2->Filter3

4. Refactoring Factory Method Design Pattern

4.1. Factory Method Pattern là gì?

Các bạn xem lại bài viết “Hướng dẫn Java Design Pattern – Factory Method“.

4.2. Ví dụ Factory Pattern

Bank.java

package com.maixuanviet.designpatterns.factory;
 
public interface Bank {
    String getBankName();
}

TPBank.java

package com.maixuanviet.designpatterns.factory;
 
public class TPBank implements Bank {
    @Override
    public String getBankName() {
        return "TPBank";
    }
}

VietcomBank.java

package com.maixuanviet.designpatterns.factory;
 
public class VietcomBank implements Bank {
    @Override
    public String getBankName() {
        return "VietcomBank";
    }
}

BankType.java

package com.maixuanviet.designpatterns.factory;
 
public enum BankType {
    VIETCOMBANK, TPBANK;
}

4.2.1. Factory Method Pattern không sử dụng Java 8

package com.maixuanviet.designpatterns.factory;
 
class BankFactory {
    public static final Bank getBank(BankType bankType) {
        switch (bankType) {
            case TPBANK:
                return new TPBank();
            case VIETCOMBANK:
                return new VietcomBank();
            default:
                throw new IllegalArgumentException("This bank type is unsupported");
        }
    }
}
 
public class FactoryMethodExample {
    public static void main(String[] args) {
        Bank bank = BankFactory.getBank(BankType.TPBANK);
        System.out.println(bank.getBankName()); // TPBank
    }
}

4.2.2. Factory Method Pattern sử dụng Supplier và Method Reference

package com.maixuanviet.designpatterns.factory;
 
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
 
class Java8BankFactory {
     
    private final static Map<BankType, Supplier<Bank>> map = new HashMap<>();
     
    static {
        map.put(BankType.TPBANK, TPBank::new);
        map.put(BankType.VIETCOMBANK, VietcomBank::new);
    }
     
    public static final Bank getBank(BankType bankType) {
        Supplier<Bank> bank = map.get(bankType);
        if (bank == null) {
            throw new IllegalArgumentException("This bank type is unsupported");
        }
        return bank.get();
    }
}
 
public class Java8FactoryMethodExample {
    public static void main(String[] args) {
        Bank bank = Java8BankFactory.getBank(BankType.TPBANK);
        System.out.println(bank.getBankName()); // TPBank
    }
}

Java 8 mang đến cho chúng ta rất nhiều tiện ích, các bạn hãy thử refactor code của mình sang Java 8 để code được gọn ràng hơn.

Related posts:

Tính kế thừa (Inheritance) trong java
So sánh HashMap và HashSet trong Java
HashSet trong Java hoạt động như thế nào?
Java Program to Compute Discrete Fourier Transform Using Naive Approach
Guide to Apache Commons CircularFifoQueue
Java Program to Implement the MD5 Algorithm
HttpClient Basic Authentication
Tìm hiểu cơ chế Lazy Evaluation của Stream trong Java 8
Java Program to Implement Sparse Array
Spring REST with a Zuul Proxy
Java Program to Implement Bucket Sort
Spring Boot - Building RESTful Web Services
Create Java Applet to Simulate Any Sorting Technique
Spring Boot: Customize the Jackson ObjectMapper
ArrayList trong java
Java Program to Find Maximum Element in an Array using Binary Search
Show Hibernate/JPA SQL Statements from Spring Boot
Java Program to Implement Hash Tables with Linear Probing
Java Program to Implement Merge Sort on n Numbers Without tail-recursion
Java Program to Implement Binary Tree
Java Program to Check Whether Graph is DAG
Java Program to Implement Binomial Tree
Comparing Strings in Java
How to Read a File in Java
Hướng dẫn sử dụng Lớp FilePermission trong java
Java Program to Check Whether an Undirected Graph Contains a Eulerian Cycle
Java Program to Implement Queue using Linked List
Spring Boot - Quick Start
Convert XML to JSON Using Jackson
Java Program to Implement Hash Tables Chaining with List Heads
Java Concurrency Interview Questions and Answers
Java Program to Check if any Graph is Possible to be Constructed for a Given Degree Sequence