Java设计模式介绍


一、构造模式

在以往的文章分享过如何改造 Java 对象实现 build 方式构建,如常见的 OkHttp 类库中就涉及到此类操作,这里就不再重复介绍,往期直达:Java Build对象构建教程

Request request = new Request.Builder()
            .url(url)
            .post(body)
            .build();

二、单例模式

单例模式即通过 volatile 与类变量的双重验证实现对象的单例创建,在之前锁的文章中介绍到 volatile 关键字时也进行了详细的阐述,往期直达:Java线程锁详解

public class Singleton {

    private volatile static Singleton instance = null;

    public static Singleton getInstance() {
        // 实例为空则获取锁
        if (instance == null) {
            synchronized (Singleton.class) {
                // synchronized 防止多线程同时初始化实例
                if (instance == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

三、工厂模式

1. 模式介绍

工厂模式是项目开发中最常涉及的设计模式,可能你已经实际应用了只是没意识到而已,同时工厂模式搭配 SPI 即可实现动态的模块打包加载。

关于 SPI 的介绍参考之前文章,往期直达:Java SPI介绍与实践

public class FactorTest {

    @Test
    public void demo() {
        AnimalFactory catFactor = new CatFactory();
        Object cat = catFactor.createAnimal();
        System.out.println(cat);

        AnimalFactory dogFactor = new DogFactory();
        Object dog = dogFactor.createAnimal();
        System.out.println(dog);
    }
}

2. 示例演示

这里以一个简单的动物工厂为例,首先创建工厂接口类 AnimalFactory 并添加工厂接口 createAnimal() 用于表示创建一类动物,而具体创建的动物类型有工厂实现者重写。

public interface AnimalFactory {

    Object createAnimal();

}

完成工厂类创建之后新建两个工厂实现者 CatFactoryDogFactory 分别对应两个不同的类别,并自定义重写工厂中的工厂方法。

工厂模式的核心思想即在于抽象提取,将同一类别的事物进行抽象,从而让代码的层级结构更为清晰。

public class CatFactory implements AnimalFactory {

    @Override
    public Object createAnimal() {
        Map<String, Object> cat = new HashMap<>();
        cat.put("Cat", new Object());
        return cat;
    }
}

public class DogFactory implements AnimalFactory {

    @Override
    public Object createAnimal() {
        Map<String, Object> cat = new HashMap<>();
        cat.put("Dog", new Object());
        return cat;
    }
}

四、策略模式

1. 模式介绍

策略模式即将对象的执行操作与触发条件进行抽象,从而避免业务逻辑中出现大量的 if else 造成程序可读性低。

public class StrategyTest {

    @Test
    public void demo() {
        Operator add = new AdditionOperator();
        if (add.isSupport(0)) {
            add.doOperate("Alex", 10);
        }

        Operator multiply = new MultiplyOperator();
        if (multiply.isSupport(1)) {
            multiply.doOperate("Beth", 10);
        }
    }
}

2. 示例演示

新增策略接口 Operator 并定义两个接口方法,分别用于指定触发条件与执行事件。

  • isSupport(): 定义事件触发需满足的条件。
  • doOperate(): 定义相应的触发执行业务逻辑。
public interface Operator {

    boolean isSupport(int type);

    void doOperate(String name, int num);
}

完成策略接口的定义之后即可进行应用,创建实现类 AdditionOperatorMultiplyOperator 分别对应加法与乘法操作。

public class AdditionOperator implements Operator {

    @Override
    public boolean isSupport(int type) {
        return type == 0;
    }

    @Override
    public void doOperate(String name, int num) {
        int res = num + 100;
        System.out.println(name + " do addition(+100), result " + res);
    }
}

public class MultiplyOperator implements Operator {

    @Override
    public boolean isSupport(int type) {
        return type == 1;
    }

    @Override
    public void doOperate(String name, int num) {
        int res = num * 100;
        System.out.println(name + " do multiply(*100), result " + res);
    }
}

五、代理模式

1. 模式介绍

代理模式顾名思义即在原有的执行逻辑顺序上添加一层代理,而不更改原有的具体业务逻辑,其执行流程如下:

在代理层应用最为广泛的即入参与出参的日志信息打印,从而在不更改业务逻辑的情况实现信息打印输出。

public class ProxyTest {

    @Test
    public void demo() {
        ProxyService proxyService = new ProxyService();
        String result = proxyService.proxySendMessage("hello");
        System.out.println(result);
    }
}

2. 示例演示

先创建 UserService 用于定义具体的业务逻辑流程,其代码如下:

public interface UserService {

    String sendMessage(String message);
}

public class UserServiceImpl implements UserService {
    @Override
    public String sendMessage(String message) {
        return "Send user message: " + message;
    }
}

完成后创建相应的代理服务 ProxyService 用于调用上述的 UserService 中对应的方法,在代理中我们可以实现调用前后的入参与出参数据打印,即可实现不修改 UserService 业务逻辑的请求下进行日志打印。

public class ProxyService {

    public String proxySendMessage(String message) {
        // Print log
        System.out.println("Proxy start log: " + message);
        // Proxy request
        UserService userService = new UserServiceImpl();
        String result = userService.sendMessage(message);
        // Print log
        System.out.println("Proxy end log: " + result);
        // Proxy request
        return result;
    }
}

六、模板模式

1. 模式介绍

模板模式即事物的操作是按照固定的流程模板运转,不同的仅仅是流程的节点的具体实现有所差异。

这里以旅行为例,其大体的流程可分为三部分:计划,出行与返回,不同的仅是这三部分具体的内容,因此我们即可定义一个固定的模板,不同的类别重写模板中的各个节点的具体内容即可。

public class TemplateTest {

    @Test
    public void demo() {
        System.out.println("============ WorkerTravel ===========");
        AbstractTravel workerTravel = new WorkerTravel();
        workerTravel.doTravel();

        System.out.println("============ TeacherTravel ===========");
        AbstractTravel teacherTravel = new TeacherTravel();
        teacherTravel.doTravel();
    }
}

2. 示例演示

新建抽象类 AbstractTravel 并定义了旅行模板 doTravel(),模板中提供了三个抽象方法表示具体的执行节点由继承者自定义重写,在对外开放的接口也仅有 doTravel() 方法。

public abstract class AbstractTravel {

    /**
     * Defined the procedure and active order.
     * <p>
     * Each extends class only need to override the abstract method.
     */
    public void doTravel() {
        plan();
        play();
        backHome();
    }

    protected abstract void plan();

    protected abstract void play();

    protected abstract void backHome();
}

新建两个类 TeacherTravelWorkerTravel 继承与 AbstractTravel 并重写其三个抽象方法,分别定义各自对象所对应的模板节点处理逻辑。

public class TeacherTravel extends AbstractTravel {
    @Override
    protected void plan() {
        System.out.println("Teacher plan.");
    }

    @Override
    protected void play() {
        System.out.println("Teacher play.");
    }

    @Override
    protected void backHome() {
        System.out.println("Teacher back home.");
    }
}

public class WorkerTravel extends AbstractTravel {
    @Override
    protected void plan() {
        System.out.println("Worker plan.");
    }

    @Override
    protected void play() {
        System.out.println("Worker play.");
    }

    @Override
    protected void backHome() {
        System.out.println("Worker backHome.");
    }
}

七、责任链模式

1. 模式介绍

责任链模式与模板模式有点类似,都是基于一定的流程,但责任链模式中的流程节点是不固定的,而模板模式的流程节点则是固定的。

责任链模式的核心在于链路,其流程是根据一定顺序执行,即一定流程节点一定存在先后关系,至于流程节点内容其并不关心。

public class ChainTest {

    @Test
    public void demo1() {
        // Set chain
        AbstractHandler h1 = new FirstHandler();
        AbstractHandler h2 = new SecondHandler();
        AbstractHandler h3 = new ThirdHandler();
        h1.nextHandler(h2);
        h2.nextHandler(h3);
        // Active chain
        HandleChain chain = new HandleChain("demo-chain");
        h1.handle(chain);
    }
}

2. 示例演示

首先创建责任链对应 HandleChain 用于定义存放链路中的数据与下一节点信息。

同时创建抽象类 AbstractHandler 用于设置链路处理逻辑与配置下级链路信息,其内容包含下述三部分。

  • handle(): 定义链路节点业务处理逻辑。
  • nextHandler(): 用于配置当前节点的下级节点。
  • invokeNext(): 当下级节点不为空时传递至下级节点。
public class HandleChain {

    private Object data;

    private HandleChain nextChain;

    public HandleChain(Object data) {
        this.data = data;
    }
}

public abstract class AbstractHandler {

    /**
     * 责任链中的下一个处理对象
     */
    protected AbstractHandler next;

    /**
     * 核心处理逻辑
     */
    public abstract void handle(HandleChain chain);

    /**
     * 设置下一个处理对象
     */
    public void nextHandler(AbstractHandler handler) {
        this.next = handler;
    }

    /**
     * 调用下一个处理对象
     */
    protected void invokeNext(HandleChain chain) {
        if (next != null) {
            next.handle(chain);
        }
    }
}

新建一个处理节点 FirstHandlerSecondHandlerThirdHandler,重写 handle() 方法实现自定义业务逻辑,并在方法结束时调用 invokeNext() 触发下一节点(在存在下级节点的情况下)。

public class FirstHandler extends AbstractHandler {

    @Override
    public void handle(HandleChain chain) {
        // Update context
        System.out.println("============= First handle ==============");
        System.out.println("Receive data: " + chain.getData());
        chain.setData("First update data.");
        // Process to next
        invokeNext(chain);
    }
}

public class SecondHandler extends AbstractHandler {

    @Override
    public void handle(HandleChain chain) {
        // Update context
        System.out.println("============= Second handle ==============");
        System.out.println("Receive data: " + chain.getData());
        chain.setData("Second update data.");
        // Process to next
        invokeNext(chain);
    }
}

public class ThirdHandler extends AbstractHandler {

    @Override
    public void handle(HandleChain chain) {
        // Update context
        System.out.println("============= Third handle ==============");
        System.out.println("Receive data: " + chain.getData());
        chain.setData("Third update data.");
        // Process to next
        invokeNext(chain);
    }
}

八、观察者模式

1. 模式介绍

观察者模式即为对象创建监听器,当事件触发时通知对应的观察者。

public class ObserverTest {

    @Test
    public void demo() {
        Listener<Observer> listener = new ObserverListener<>();
        // Register listener
        listener.register(new StatusObserver("Status-1"));
        listener.register(new StatusObserver("Status-2"));
        listener.register(new ObjectObserver("Object-1"));
        listener.register(new ObjectObserver("Object-2"));
        // Send notification
        listener.notify("Hello, World!");
    }
}

2. 示例演示

首先新建观察者对象 Observer 与监听器工厂 Listener 并实现了一个观察者监听器 ObserverListener

其中观察者用于接收事件通知,监听器工厂中定义了三个主要事件:

  • register(): 添加观察者对象。
  • remove(): 移除观察者对象。
  • notify(): 通知已添加注册的观察者。
public interface Listener<T> {

    void register(T t);

    void remove(T t);

    void notify(String t);
}


public interface Observer {

    void received(String message);

}

public class ObserverListener<T extends Observer> implements Listener<T> {

    private final List<T> listenerList = new CopyOnWriteArrayList<>();

    @Override
    public void register(T t) {
        listenerList.add(t);
    }

    @Override
    public void remove(T t) {
        listenerList.add(t);
    }

    @Override
    public void notify(String message) {
        for (T t : listenerList) {
            t.received(message);
        }
    }
}

完成后实现 Observer 类创建不同类型的观察者对象用于事件的观察监听。

public class ObjectObserver implements Observer {

    private String name;

    public ObjectObserver(String name) {
        this.name = name;
    }

    @Override
    public void received(String message) {
        System.out.printf("%s received message: %s%n", name, message);
    }
}

public class StatusObserver implements Observer {

    private String name;

    public StatusObserver(String name) {
        this.name = name;
    }

    @Override
    public void received(String message) {
        System.out.printf("%s received message: %s%n", name, message);
    }
}

九、标记模式

1. 模式介绍

标记模式其实很简单,即通过一个空接口用于表示标记,如 Java 中序列化接口 Serializable,其并没有定义任意内容,仅起到标记内容,如果一个类没有实现该接口,则说明不支持该操作。

public class MarkTest {

    private static final List<Object> objList = new ArrayList<>();

    @Test
    public void markDemo() {
        try {
            putContainer(new EnableMark());
        } catch (UnsupportedOperationException e) {
            System.err.println(e.getMessage());
        }

        try {
            putContainer(new DisableMark());
        } catch (UnsupportedOperationException e) {
            System.err.println(e.getMessage());
        }
        System.out.println(objList);
    }

    private void putContainer(Object obj) {
        Class<?> clazz = obj.getClass();
        Class<?> markCls = Marker.class;
        if (markCls.isAssignableFrom(clazz)) {
            System.out.printf("Class [%s] is supported.\n", clazz.getName());
            objList.add(obj);
        } else {
            throw new UnsupportedOperationException("The class [" + clazz.getName() + "] is not supported putContainer().");
        }
    }
}

2. 示例演示

标记模式的定义相对简单,新建空接口 Marker,若一个类实现了 Marker 表示支持标记,在程序中即可通过 isAssignableFrom() 方法返回是否实现了该接口类。

public interface Marker {

}

public class DisableMark {

}

public class EnableMark implements Marker {

}

十、回调模式

1. 模式介绍

在传统的方法定义中,若一个方法不为 void 则结果都是通过 return 进行返回,而返回则是通过回调在方法入参进行返回。

public class CallbackTest {

    @Test
    public void demo1() {
        props = new Properties();
        props.put("message", "Hello World!");

        FutureEvent.callback(props, caller -> {
            String key = caller.getProperty("message");
            System.out.println("Receive message: " + key);
        });
    }

    @Test
    public void demo2() {
        props = new Properties();
        props.put("message", "Hello World!");

        FutureEvent.activated(props, new EventHandle<Properties>() {
            @Override
            public void success(Properties props) {
                String key = props.getProperty("message");
                System.out.println("Receive message: " + key);
            }

            @Override
            public void failed(Throwable e, Properties props) {
                System.err.println("Capture exception: " + e.getMessage());
            }
        });
    }
}

2. 示例演示

常见的回调方式有以下两类:

  • 第一类:将执行完成后的结果通过回调返回。
  • 第二类:将执行结果拆分,提供结果接口与异常接口。

上述二者回调接口具体定义内容如下:

public interface Callback<T> {

    void callback(T t);

}

public interface EventHandle<T> {

    void success(T data);

    void failed(Throwable e, T data);

}

public class FutureEvent {

    public static <T> void callback(T t, Callback<T> caller) {
        // do something to "props" then transfer it

        caller.callback(t);
    }

    public static <T> void activated(T t, EventHandle<T> handle) {
        try {
            if (false) {
                throw new IllegalArgumentException("illegal");
            }

            // do something to data(t) then transfer it
            handle.success(t);
        } catch (Exception e) {
            handle.failed(e, t);
        }
    }
}

参考文章

  1. 两万字盘点被玩烂了的9种设计模式

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录