设计模式之行为型设计模式

1.简介

        行为型设计模式是一类关注对象间的通信和交互的设计模式,它们用于解决对象之间的职责分配和协作问题。这些模式描述了对象之间如何协作以完成单个任务,以及如何保持对象之间的松散耦合性。

        行为型设计模式可分为以下几类:

        1.模板方法模式(Template Method Pattern):定义一个算法框架,允许子类为一个或多个步骤提供实现。

        2.观察者模式(Observer Pattern):定义对象之间的一对多依赖,使得当一个对象状态发生改变时,所有依赖它的对象都会得到通知并自动更新。

        3.策略模式(Strategy Pattern):定义一系列算法,将它们封装成独立的类,并使它们可以互相替换,从而使算法的变化独立于使用它们的客户端。

        4.命令模式(Command Pattern):将请求封装成对象,从而允许使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销的操作。

        5.状态模式(State Pattern):允许对象在其内部状态改变时改变其行为。对象看起来似乎修改了其类。

        6.职责链模式(Chain of Responsibility Pattern):通过一条链式结构来组织请求的处理者,使得每个请求都可以被处理多次,直到有一个处理者处理为止。

        7.解释器模式(Interpreter Pattern):定义一种语言,解析该语言的一种表示,并执行所表示的操作。

        8.访问者模式(Visitor Pattern):定义一个新的操作,将其应用于一组对象上。访问者模式可以使得操作独立于对象的类别。

2.模板方法模式

        模板方法模式是一种行为型设计模式,它定义了一个算法的框架,将一些步骤的具体实现推迟到子类中,以便不同的子类可以根据自己的实际需求来实现这些步骤。

        在模板方法模式中,定义了一个抽象类,其中包含了一个或多个抽象方法,这些抽象方法可以被子类实现,同时还包含了一个具体的模板方法,该方法中调用了抽象方法以完成特定的算法流程。

        下面是一个简单的示例代码:

abstract class AbstractClass {
    public void templateMethod() {
        // step 1
        operation1();
        // step 2
        operation2();
        // step 3
        operation3();
    }

    protected abstract void operation1();
    protected abstract void operation2();

    protected void operation3() {
        // 默认实现,子类可以选择重写
    }
}

class ConcreteClass1 extends AbstractClass {
    @Override
    protected void operation1() {
        System.out.println("ConcreteClass1 operation1");
    }

    @Override
    protected void operation2() {
        System.out.println("ConcreteClass1 operation2");
    }
}

class ConcreteClass2 extends AbstractClass {
    @Override
    protected void operation1() {
        System.out.println("ConcreteClass2 operation1");
    }

    @Override
    protected void operation2() {
        System.out.println("ConcreteClass2 operation2");
    }

    @Override
    protected void operation3() {
        System.out.println("ConcreteClass2 operation3");
    }
}

        在这个示例代码中,AbstractClass 是一个抽象类,其中定义了一个模板方法 templateMethod(),其中包含了三个步骤:operation1()operation2()operation3()。其中 operation1()operation2() 是抽象方法,需要由子类来实现,而 operation3() 是一个默认实现的方法,子类可以选择重写或不重写。

  ConcreteClass1ConcreteClass2 分别是两个具体子类,它们继承了 AbstractClass 并实现了其中的抽象方法。ConcreteClass2 重写了 operation3() 方法,覆盖了默认实现。

        模板方法模式常用于框架设计中,框架定义了算法的框架,而具体实现由子类来完成。例如,Java 中的 Servlet 规范中,定义了一个 doGet() 方法,该方法包含了 HTTP 请求处理的整个流程,而具体的实现由 Servlet 子类来完成。

        另一个使用模板方法模式的例子是 GUI 库中的窗口类。窗口类定义了打开、关闭、渲染等操作的框架,而具体的实现由子类来完成。

        总之,模板方法模式可以帮助我们实现复杂的算法,并且在实现过程中可以保证算法的一致性和可扩展性。

3.观察者模式

        观察者模式(Observer Pattern)属于行为型设计模式,其定义了一种一对多的依赖关系,当被观察者的状态发生变化时,它的所有依赖者都会收到通知并自动更新。

观察者模式由以下角色组成:

  • Subject:被观察者,定义了添加、删除和通知观察者的接口。
  • Observer:观察者,定义了接收通知和更新状态的接口。
  • ConcreteSubject:具体的被观察者,维护一份自己的观察者列表,并负责通知观察者状态的变化。
  • ConcreteObserver:具体的观察者,维护一个指向具体的被观察者的引用,并实现自己的更新方法。

下面是一个简单的观察者模式的示例代码:

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

interface Observer {
    void update(String message);
}

interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers(String message);
}

class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

class ConcreteObserver implements Observer {
    private String name;

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

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

public class ObserverDemo {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Observer observer1 = new ConcreteObserver("Observer1");
        Observer observer2 = new ConcreteObserver("Observer2");

        subject.attach(observer1);
        subject.attach(observer2);

        subject.notifyObservers("Hello World!");

        subject.detach(observer2);

        subject.notifyObservers("Goodbye World!");
    }
}

        在这个示例中,ConcreteSubject 充当了被观察者的角色,ConcreteObserver 充当了观察者的角色。当 ConcreteSubject 的状态发生变化时,它会通知所有观察者,并调用它们的 update 方法。

在Java中,观察者模式也有很多应用场景,以下是一些例子:

        1.Java自带的事件监听机制

Java AWT和Swing组件库都使用了观察者模式来实现事件监听器的机制。当一个事件发生时,Java会调用注册在事件源上的监听器的方法。

        2.Spring框架的事件监听器机制

在Spring框架中,通过使用ApplicationEvent和ApplicationListener接口,实现了一套灵活的事件监听机制。当应用程序中的某个事件发生时,Spring容器会通知所有注册的监听器。

        3.Guava EventBus

        Google Guava库中提供了一个事件总线框架,可以让开发人员更方便地实现事件驱动的编程。事件总线框架基于观察者模式,使用了反射和动态代理等技术,实现了一个高效的事件分发机制。

3.策略模式

        策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法都封装起来,使它们可以相互替换。这使得算法的变化可以独立于使用它们的客户端。

下面是一个策略模式的示例代码:

// 策略接口
public interface SortingStrategy {
    public void sort(int[] arr);
}

// 快速排序策略
public class QuickSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] arr) {
        // 实现快速排序算法
    }
}

// 归并排序策略
public class MergeSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] arr) {
        // 实现归并排序算法
    }
}

// 策略上下文
public class Sorter {
    private SortingStrategy strategy;

    public void setStrategy(SortingStrategy strategy) {
        this.strategy = strategy;
    }

    public void sort(int[] arr) {
        strategy.sort(arr);
    }
}

// 客户端代码
public static void main(String[] args) {
    int[] arr = {5, 2, 8, 6, 1, 9};

    Sorter sorter = new Sorter();
    sorter.setStrategy(new QuickSortStrategy());
    sorter.sort(arr); // 快速排序

    sorter.setStrategy(new MergeSortStrategy());
    sorter.sort(arr); // 归并排序
}

        在上面的示例代码中,我们定义了一个SortingStrategy接口和两个具体的算法类QuickSortStrategyMergeSortStrategy,它们都实现了SortingStrategy接口。然后我们定义了一个Sorter类,它持有一个SortingStrategy接口类型的成员变量,可以设置不同的算法实现。最后,在客户端代码中,我们可以通过调用Sorter对象的setStrategy()方法来设置不同的算法,然后调用sort()方法来进行排序。

        策略模式的优点在于,它可以让算法的变化独立于使用它的客户端。客户端代码可以使用不同的算法,而不需要改变自己的实现。另外,策略模式还可以避免使用大量的条件语句,使代码更加简洁和可读。

        一个实际应用策略模式的例子是在线购物网站的结算系统。结算系统需要根据用户选择的支付方式来计算商品的价格。不同的支付方式可能有不同的优惠政策,因此可以将不同的支付方式实现为不同的策略类,然后在结算系统中使用策略模式来选择合适的支付策略进行计算。这样就可以方便地添加或修改支付方式,而不需要修改结算系统的代码。

4.责任链模式

        责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行发送,直到有一个处理者处理请求为止。每个处理者都有一个对下一个处理者的引用,从而形成了一个链。

        在责任链模式中,客户端向处理器链中的第一个处理器发送请求,然后链中的每个处理器都有机会来处理该请求。如果处理器能够处理该请求,则处理请求并返回结果;否则,它会将请求传递给链中的下一个处理器,直到请求被处理为止。

        一个简单的责任链模式示例可以是一个网站的反作弊系统。当用户在网站上进行某些活动时,如提交评论、发布帖子等,系统会对其进行验证,以确保其不是机器人。该系统通常由多个阶段组成,每个阶段都有不同的验证机制。如果在一个阶段中未能通过验证,请求将被传递到下一个阶段进行处理,直到请求被验证通过或全部阶段都未能通过验证为止。

        以下是一个简单的Java实现示例:

public abstract class Handler {
    private Handler nextHandler;

    public Handler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void handleRequest(Request request) {
        if (canHandleRequest(request)) {
            handle(request);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        } else {
            System.out.println("No handler found for the request.");
        }
    }

    protected abstract boolean canHandleRequest(Request request);

    protected abstract void handle(Request request);
}

public class Request {
    private String message;

    public Request(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

public class AuthenticationHandler extends Handler {
    public AuthenticationHandler(Handler nextHandler) {
        super(nextHandler);
    }

    @Override
    protected boolean canHandleRequest(Request request) {
        return request.getMessage().startsWith("authenticate:");
    }

    @Override
    protected void handle(Request request) {
        System.out.println("Authenticating the request: " + request.getMessage());
    }
}

public class AuthorizationHandler extends Handler {
    public AuthorizationHandler(Handler nextHandler) {
        super(nextHandler);
    }

    @Override
    protected boolean canHandleRequest(Request request) {
        return request.getMessage().startsWith("authorize:");
    }

    @Override
    protected void handle(Request request) {
        System.out.println("Authorizing the request: " + request.getMessage());
    }
}

public class Main {
    public static void main(String[] args) {
        Handler handlerChain = new AuthenticationHandler(new AuthorizationHandler(null));

        Request request1 = new Request("authenticate:user1");
        handlerChain.handleRequest(request1);

        Request request2 = new Request("authorize:user2");
        handlerChain.handleRequest(request2);

        Request request3 = new Request("invalid_request");
        handlerChain.handleRequest(request3);
    }
}

        责任链模式在许多开源框架中得到了广泛应用,以下是一些例子:

  1. Java Servlet API 中的 Filter 模式,其中每个 Filter 都可以拦截请求并进行处理。请求首先由第一个 Filter 处理,然后依次传递到下一个 Filter,直到请求被处理为止。

  2. Spring Framework 中的 AOP(Aspect Oriented Programming)就是基于责任链模式实现的。Spring AOP 允许将一个横切关注点(如事务管理、日志记录等)与应用程序的业务逻辑分离开来,并通过一系列的增强器将它们织入到目标对象的方法调用中。

  3. Apache Tomcat 中的 Valve 模式。Tomcat 是一个开源的 Web 容器,它使用了一种叫做 Valve 的模式来实现许多功能,如 HTTP 请求过滤、访问控制等。每个 Valve 都可以处理请求,然后将请求传递给下一个 Valve,直到请求被处理完毕。

  4. Netty 中的 ChannelPipeline 模式。Netty 是一个基于 NIO 的高性能网络应用框架,它采用了责任链模式来实现数据的处理和传递。Netty 中的 ChannelPipeline 包含了一系列的 ChannelHandler,每个 Handler 都可以对数据进行处理,并将数据传递给下一个 Handler。

        总之,责任链模式是一种非常常用的设计模式,可以帮助我们将请求的处理过程拆分成多个步骤,并且允许我们动态地修改处理流程。这样可以使系统更加灵活、可扩展,提高系统的可维护性和可复用性。

5.解释器模式

        解释器模式是一种行为型设计模式,用于解决一些特定问题。该模式的核心思想是定义一个语言文法,并定义解释器来解释该语言中的语句。解释器模式主要由以下两部分组成:

  1. 抽象表达式(Abstract Expression):定义解释器的接口,该接口通常只包含一个 interpret() 方法。
  2. 具体表达式(Concrete Expression):实现抽象表达式接口,对表达式进行具体解释。

        下面是一个解释器模式的简单示例:

// 抽象表达式
interface Expression {
    boolean interpret(String context);
}

// 具体表达式
class TerminalExpression implements Expression {
    private String data;

    public TerminalExpression(String data) {
        this.data = data;
    }

    @Override
    public boolean interpret(String context) {
        if (context.contains(data)) {
            return true;
        }
        return false;
    }
}

// 或表达式
class OrExpression implements Expression {
    private Expression expression1;
    private Expression expression2;

    public OrExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }

    @Override
    public boolean interpret(String context) {
        return expression1.interpret(context) || expression2.interpret(context);
    }
}

// 与表达式
class AndExpression implements Expression {
    private Expression expression1;
    private Expression expression2;

    public AndExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }

    @Override
    public boolean interpret(String context) {
        return expression1.interpret(context) && expression2.interpret(context);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Expression robert = new TerminalExpression("Robert");
        Expression john = new TerminalExpression("John");
        Expression orExpression = new OrExpression(robert, john);
        Expression julie = new TerminalExpression("Julie");
        Expression married = new TerminalExpression("Married");
        Expression andExpression = new AndExpression(julie, married);
        System.out.println(orExpression.interpret("John"));
        System.out.println(andExpression.interpret("Julie Married"));
    }
}

        解释器模式在Java中的使用相对较少,不过在一些领域特定语言的解析中还是有应用的,比如在数据库查询语言中的解析、正则表达式解析等。

        以正则表达式为例,Java中的java.util.regex包就是基于解释器模式实现的。在这个包中,Pattern类表示正则表达式模式,而Matcher类则表示对模式进行匹配的结果。在进行匹配时,Pattern会将正则表达式编译成一个解释器对象,然后通过Matcher类来对输入的字符串进行解析和匹配。

        具体地,Pattern类使用了解释器模式中的组合模式来组合多个解释器对象,从而构建出整个正则表达式的解释器对象树。这个树结构包括多个叶子节点,每个叶子节点表示一个基本的正则表达式语法元素,比如一个字符或者一个字符类,而非叶子节点则表示多个基本元素的组合,比如一个或多个字符的重复或者多个字符类的并集。Matcher类则使用了迭代器模式来遍历这个解释器对象树,对输入的字符串进行解析和匹配。

        总之,解释器模式在Java中的应用比较特定,一般都是在领域特定语言的解析或者类似正则表达式这样的特定场景中使用。

猜你喜欢

转载自blog.csdn.net/zz18532164242/article/details/130395027