Backend Development 11 min read

Refactoring Classic Design Patterns with Java 8 Features: Strategy, Template Method, Observer, and Chain of Responsibility

This article demonstrates how Java 8's lambda expressions and functional interfaces can simplify traditional implementations of the Strategy, Template Method, Observer, and Chain‑of‑Responsibility design patterns by reducing boilerplate code and consolidating multiple classes into concise functional constructs.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Refactoring Classic Design Patterns with Java 8 Features: Strategy, Template Method, Observer, and Chain of Responsibility

Hello everyone, I am Chen.

Java 8 introduces many new features that can be used to refactor traditional design‑pattern implementations; the following sections provide concrete examples.

1. Strategy Pattern

The diagram shows the classic Strategy pattern for saving orders. The OrderService interface defines the operation, while NoSqlSaveOrderStrategy and MySqlSaveOrderStrategy provide two concrete strategies for persisting to NoSQL and MySQL respectively. The OrderServiceExecutor receives a strategy via constructor injection.

public interface OrderService {
    void saveOrder(String orderNo);
}
public class MySqlSaveOrderStrategy implements OrderService {
    @Override
    public void saveOrder(String orderNo) {
        System.out.println("order:" + orderNo + " save to mysql");
    }
}
public class NoSqlSaveOrderStrategy implements OrderService {
    @Override
    public void saveOrder(String orderNo) {
        System.out.println("order:" + orderNo + " save to nosql");
    }
}
public class OrderServiceExecutor {
    private final OrderService service;
    public OrderServiceExecutor(OrderService service) {
        this.service = service;
    }
    public void save(String orderNo) {
        this.service.saveOrder(orderNo);
    }
}
public class OrderServiceTest {
    public static void main(String[] args) {
        OrderServiceExecutor executor1 = new OrderServiceExecutor(new MySqlSaveOrderStrategy());
        executor1.save("001");
        OrderServiceExecutor executor2 = new OrderServiceExecutor(new NoSqlSaveOrderStrategy());
        executor2.save("002");
    }
}

Using Java 8, the two concrete strategy classes can be replaced with lambda expressions, reducing the code to:

public static void main(String[] args) {
    OrderServiceExecutor executor1 = new OrderServiceExecutor((orderNo) ->
        System.out.println("order:" + orderNo + " save to mysql"));
    executor1.save("001");

    OrderServiceExecutor executor2 = new OrderServiceExecutor((orderNo) ->
        System.out.println("order:" + orderNo + " save to nosql"));
    executor2.save("002");
}

2. Template Method Pattern

The classic template method defines the invariant workflow in an abstract class and leaves the variable part to subclasses. The example shows a push‑notification system where different shops may send coupons or points.

public abstract class AbstractPushTemplate {
    public void push(int customerId, String shopName) {
        System.out.println("准备推送...");
        execute(customerId, shopName);
        System.out.println("推送完成\n");
    }
    protected abstract void execute(int customerId, String shopName);
}
public class PushCouponTemplate extends AbstractPushTemplate {
    @Override
    protected void execute(int customerId, String shopName) {
        System.out.println("会员:" + customerId + ",你好," + shopName + "送您一张优惠券");
    }
}
public class PushScoreTemplate extends AbstractPushTemplate {
    @Override
    protected void execute(int customerId, String shopName) {
        System.out.println("会员:" + customerId + ",你好," + shopName + "送您10个积分");
    }
}
AbstractPushTemplate template1 = new PushCouponTemplate();
template1.push(1, "糖果店");

AbstractPushTemplate template2 = new PushScoreTemplate();
template2.push(1, "服装店");

With Java 8 the three classes can be collapsed into a single lambda‑based template:

public class PushTemplateLambda {
    public void push(int customerId, String shopName, Consumer
execute) {
        System.out.println("准备推送...");
        Object[] param = new Object[]{customerId, shopName};
        execute.accept(param);
        System.out.println("推送完成\n");
    }
}
new PushTemplateLambda().push(1, "糖果店", (obj) -> {
    System.out.println("会员:" + obj[0] + ",你好," + obj[1] + "送您一张优惠券");
});

new PushTemplateLambda().push(1, "服装店", (obj) -> {
    System.out.println("会员:" + obj[0] + ",你好," + obj[1] + "送您10个积分");
});

3. Observer Pattern

The classic observer pattern consists of a Subject that maintains a list of Observer instances and notifies them when an event occurs.

public interface Observer {
    void notify(String orderNo);
}
public interface Subject {
    void registerObserver(Observer o);
    void notifyAllObserver(String orderNo);
}
public class SubjectImpl implements Subject {
    private final List
list = new ArrayList<>();
    @Override
    public void registerObserver(Observer o) {
        list.add(o);
    }
    @Override
    public void notifyAllObserver(String orderNo) {
        list.forEach(c -> c.notify(orderNo));
    }
}
public class OrderObserver implements Observer {
    @Override
    public void notify(String orderNo) {
        System.out.println("订单 " + orderNo + " 状态更新为【已支付】");
    }
}
public class StockObserver implements Observer {
    @Override
    public void notify(String orderNo) {
        System.out.println("订单 " + orderNo + " 已通知库房发货!");
    }
}
static void test1() {
    Subject subject = new SubjectImpl();
    subject.registerObserver(new OrderObserver());
    subject.registerObserver(new StockObserver());
    subject.notifyAllObserver("001");
}

Java 8 allows default methods in interfaces, enabling a new NewSubject that provides the same functionality with only two interfaces and lambda expressions:

public interface NewSubject {
    List
list = new ArrayList<>();
    default void registerObserver(Observer o) { list.add(o); }
    default void nofityAllObserver(String orderNo) { list.forEach(c -> c.notify(orderNo)); }
}
static void test2() {
    NewSubject subject = new NewSubject() {};
    subject.registerObserver((orderNo) -> System.out.println("订单 " + orderNo + " 状态更新为【已支付】"));
    subject.registerObserver((orderNo) -> System.out.println("订单 " + orderNo + " 已通知库房发货!"));
    subject.nofityAllObserver("002");
}

4. Chain of Responsibility (Responsibility) Pattern

The classic implementation uses a linked list of processor objects, each delegating to the next.

public interface Processor {
    Processor getNextProcessor();
    void process(String param);
}
public abstract class AbstractProcessor implements Processor {
    private Processor next;
    public AbstractProcessor(Processor processor) { this.next = processor; }
    @Override public Processor getNextProcessor() { return next; }
    @Override public abstract void process(String param);
}
public class ProcessorImpl1 extends AbstractProcessor {
    public ProcessorImpl1(Processor processor) { super(processor); }
    @Override public void process(String param) {
        System.out.println("processor 1 is processing:" + param);
        if (getNextProcessor() != null) {
            getNextProcessor().process(param);
        }
    }
}
public class ProcessorImpl2 extends AbstractProcessor {
    public ProcessorImpl2(Processor next) { super(next); }
    @Override public void process(String param) {
        System.out.println("processor 2 is processing:" + param);
        if (getNextProcessor() != null) {
            getNextProcessor().process(param);
        }
    }
}
static void test1() {
    Processor p1 = new ProcessorImpl1(null);
    Processor p2 = new ProcessorImpl2(p1);
    p2.process("something happened");
}

Java 8 can replace the whole hierarchy with a single functional interface:

@FunctionalInterface
public interface NewProcessor {
    Consumer
process(String param);
}
static void test2() {
    Consumer
p1 = param -> System.out.println("processor 1 is processing:" + param);
    Consumer
p2 = param -> System.out.println("processor 2 is processing:" + param);
    p2.andThen(p1).accept("something happened");
}

The author also provides a list of recommended reading links and asks readers to like, share, and follow.

chain of responsibilitydesign patternsJavaJava8template methodstrategyObserver
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.