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

Bài viết được sự cho phép của tác giả Giang Phan

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 , Function, Supplier, … để refactor code của một số Design Pattern.

Xem thêm nhiều việc làm Java lương cao trên TopDev

Refactoring Strategy Design Pattern

Strategy.java

package com.gpcoder.designpatterns.strategy;

public interface Strategy {
void performTask();
}

Strategy Pattern không sử dụng Lambda

StartegyPatternExample.java

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 strategies = Arrays.asList(eagerStrategy, lazyStrategy);
for (Strategy stg : strategies) {
stg.performTask();
}
}
}

Strategy Pattern sử dụng Lambda

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 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.

  30 tiện ích Chrome (extensions) cho Designer và Developer
  30 tiện ích Chrome cho designer và dev

Refactoring Observer Design Pattern

Observer.java

package com.gpcoder.designpatterns.observer;

public interface Observer {
void update(String str);
}

Subject.java

package com.gpcoder.designpatterns.observer;

public interface Subject {

void registerObserver(Observer observer);

void notifyObservers(String str);
}

AccountService.java

package com.gpcoder.designpatterns.observer;

import java.util.ArrayList;
import java.util.List;

public class AccountService implements Subject {

private final List 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 không sử dụng Lambda

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 sử dụng Lambda

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");
}
}

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

Login: gpcoder
Logger: gpcoder
Mailer: gpcoder

Refactoring Chain of Responsibility Pattern

Filter.java

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 không sử dụng Lambda

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 sử dụng Lambda và Function

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 filter1 = (str) -> {
System.out.println("Filter1: " + str);
return str + "->Filter1";
};

UnaryOperator filter2 = (str) -> {
System.out.println("Filter2: " + str);
return str + "->Filter2";
};

UnaryOperator 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);
}
}

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: gpcoder
Filter2: gpcoder->Filter1
Filter3: gpcoder->Filter1->Filter2
Final data: gpcoder->Filter1->Filter2->Filter3

Refactoring Factory Method Design Pattern

Bank.java

package com.gpcoder.designpatterns.factory;

public interface Bank {
String getBankName();
}

TPBank.java

package com.gpcoder.designpatterns.factory;

public class TPBank implements Bank {
@Override
public String getBankName() {
return "TPBank";
}
}

VietcomBank.java

package com.gpcoder.designpatterns.factory;

public class VietcomBank implements Bank {
@Override
public String getBankName() {
return "VietcomBank";
}
}

BankType.java

package com.gpcoder.designpatterns.factory;

public enum BankType {
VIETCOMBANK, TPBANK;
}

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

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 sử dụng Supplier và Method Reference

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> 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 = 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.

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng công nghệ thông tin hấp dẫn trên TopDev