In this article, I will show you how to use some new features in Java 8 such as Lambda , Function , Supplier , etc. to refactor the code of some Design Pattern .
Refactoring Strategy Design Pattern
What is strategy pattern?
You review the article ” Tutorial Java Design Pattern – Strategy “.
For example Strategy Pattern
Strategy.java
1 2 3 4 5 6 | package com.gpcoder.designpatterns.strategy; public interface Strategy { void performTask(); } |
Strategy Pattern does not use Lambda
StartegyPatternExample.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package com.gpcoder.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(); } } } |
Strategy Pattern uses Lambda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package com.gpcoder.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()); } } |
Refactoring Observer Design Pattern
What is the Observer Pattern?
Have you reviewed the article ” Tutorial Java Design Pattern – Observer “.
Example Observer Pattern
Observer.java
1 2 3 4 5 6 | package com.gpcoder.designpatterns.observer; public interface Observer { void update(String str); } |
Subject.java
1 2 3 4 5 6 7 8 9 | package com.gpcoder.designpatterns.observer; public interface Subject { void registerObserver(Observer observer); void notifyObservers(String str); } |
AccountService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.gpcoder.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); } } } |
Observer Pattern does not use Lambda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package com.gpcoder.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("gpcoder"); } } |
Observer Pattern uses Lambda
1 2 3 4 5 6 7 8 9 10 11 12 13 | package com.gpcoder.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("gpcoder"); } } |
Running the above 2 programs, we get the same results:
1 2 3 4 | Login: gpcoder Logger: gpcoder Mailer: gpcoder |
Refactoring Chain of Responsibility Pattern
What is the Chain of Responsibility Pattern?
Have you reviewed the article ” Tutorial Java Design Pattern – Chain of Responsibility “.
Example of Chain of Responsibility Pattern
Filter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.gpcoder.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); } |
Chain of Responsibility Pattern does not use Lambda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package com.gpcoder.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("gpcoder"); System.out.println("Final data: " + result); } } |
Chain of Responsibility Pattern uses Lambda and Function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package com.gpcoder.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("gpcoder"); System.out.println("Final data: " + result); } } |
Note: UnaryOperator is a Function, has the same input and output data types. UnaryOperator <String> is equivalent to writing Function <String, String>.
Running the above 2 programs, we have the same result:
1 2 3 4 5 | Filter1: gpcoder Filter2: gpcoder->Filter1 Filter3: gpcoder->Filter1->Filter2 Final data: gpcoder->Filter1->Filter2->Filter3 |
Refactoring Factory Method Design Pattern
What is the Factory Method Pattern?
Have you reviewed the article ” Tutorial Java Design Pattern – Factory Method “.
Example Factory Pattern
Bank.java
1 2 3 4 5 6 | package com.gpcoder.designpatterns.factory; public interface Bank { String getBankName(); } |
TPBank.java
1 2 3 4 5 6 7 8 9 | package com.gpcoder.designpatterns.factory; public class TPBank implements Bank { @Override public String getBankName() { return "TPBank"; } } |
VietcomBank.java
1 2 3 4 5 6 7 8 9 | package com.gpcoder.designpatterns.factory; public class VietcomBank implements Bank { @Override public String getBankName() { return "VietcomBank"; } } |
BankType.java
1 2 3 4 5 6 | package com.gpcoder.designpatterns.factory; public enum BankType { VIETCOMBANK, TPBANK; } |
Factory Method Pattern does not use Java 8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.gpcoder.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 } } |
Factory Method Pattern uses Supplier and Method Reference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package com.gpcoder.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 brings us a lot of utilities, you should try refactor your code to Java 8 to make the code cleaner.
Original article link: https://gpcoder.com/6200-refactoring-design-pattern-voi-tinh-nang-moi-rong-java-8/