Java 23种设计模式介绍以及代码示例 第三篇行为型设计模式

简介: 使用行为型设计模式可以帮助我们更好地组织和管理对象之间的交互行为,提高代码的可重用性、可扩展性和维护性。下面是一些在Java中使用行为型设计模式的理由:1. 利于代码的重用:通过使用行为型设计模式,我们可以将通用的行为逻辑封装到可重用的组件中,减少重复编写代码的工作量。2. 降低耦合度:行为型设计模式将对象之间的交互行为解耦,使得各个对象之间的依赖性降低,从而提高了系统的灵活性和可维护性。3. 提高代码的可扩展性:通过使用行为型设计模式,我们可以方便地添加新的行为或修改现有的行为,而不需要修改已有的代码,减少了对原有代码的影响。4. 提高代码的可读性:行为型设计模式将不同的行为

 行为型设计模式

一,介绍

image.gif编辑

使用行为型设计模式可以帮助我们更好地组织和管理对象之间的交互行为,提高代码的可重用性、可扩展性和维护性。下面是一些在Java中使用行为型设计模式的理由:

1. 利于代码的重用:通过使用行为型设计模式,我们可以将通用的行为逻辑封装到可重用的组件中,减少重复编写代码的工作量。

2. 降低耦合度:行为型设计模式将对象之间的交互行为解耦,使得各个对象之间的依赖性降低,从而提高了系统的灵活性和可维护性。

3. 提高代码的可扩展性:通过使用行为型设计模式,我们可以方便地添加新的行为或修改现有的行为,而不需要修改已有的代码,减少了对原有代码的影响。

4. 提高代码的可读性:行为型设计模式将不同的行为和算法进行了明确的封装和划分,使得代码更易于理解和维护。

5. 促进代码的解耦和灵活性:行为型设计模式允许我们将不同的行为和算法独立于具体的类,从而实现了代码的解耦和灵活性,方便进行组合和替换。

不过,在使用行为型设计模式时,我们也需要注意合适的场景和适度的使用,避免过度设计和增加代码的复杂性。根据具体的需求和情况选择合适的设计模式,可以帮助我们更好地设计和开发Java应用程序。

二,访问者模式

1.介绍

访问者模式(Visitor Pattern)是一种行为型设计模式,它能够对不同的对象结构进行遍历,并在不修改这些对象的前提下定义新的操作。通过使用访问者模式,我们可以将数据结构与作用于数据结构上的操作分离开来,从而使得操作集合可以独立变化而不影响数据结构。

这种模式属于对象行为型模式。

2.代码示例

下面是一个示例的 Java 实现:

首先我们定义两个接口:

// 表示被访问的元素的接口
public interface Element {
    void accept(Visitor visitor);
}
// 表示访问行为(操作)的接口
public interface Visitor {
    void visit(Element element);
}

image.gif

然后,我们定义实现 Element 接口的具体元素类,以及实现 Visitor 接口的具体访问者类:

 

// 具体元素A
public class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationA() {
        System.out.println("ConcreteElementA operationA.");
    }
}
// 具体元素B
public class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationB() {
        System.out.println("ConcreteElementB operationB.");
    }
}
// 具体访问者
public class ConcreteVisitor implements Visitor {
    @Override
    public void visit(Element element) {
        if (element instanceof ConcreteElementA) {
            ((ConcreteElementA) element).operationA();
        } else if (element instanceof ConcreteElementB) {
            ((ConcreteElementB) element).operationB();
        } else {
            throw new IllegalArgumentException("Unknown element type.");
        }
    }
}

image.gif

最后,我们可以创建具体的对象结构,并使用访问者进行遍历和操作:

 

public class Client {
    public static void main(String[] args) {
        List<Element> elements = Arrays.asList(new ConcreteElementA(), new ConcreteElementB());
        Visitor visitor = new ConcreteVisitor();
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

image.gif

在上述示例中,我们通过 ConcreteVisitor 类实现了对 ConcreteElementA 和 ConcreteElementB 两个具体元素的访问行为。客户端使用 accept 方法将各个元素传递给访问者进行访问和操作。

需要注意的是,该示例中的元素只有两种类型,实际使用中可能需要支持更多类型的元素,访问者的实现也需要相应地进行调整。

三,模板方法

1.介绍

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的骨架,将某些步骤的具体实现延迟到子类中。在模板方法模式中,将通用的算法逻辑放在抽象类中,而具体的实现细节由子类来完成。

这种模式属于对象行为型模式。

2.代码示例

下面是一个示例的 Java 实现:

首先,我们定义一个抽象类,其中包含了模板方法以及一些基本操作的抽象方法:

 

public abstract class AbstractClass {
    // 模板方法
    public final void templateMethod() {
        // 调用基本操作方法
        operation1();
        operation2();
        // 可选调用钩子方法
        if (hookMethod()) {
            operation3();
        }
    }
    // 基本操作方法,由子类具体实现
    protected abstract void operation1();
    protected abstract void operation2();
    // 钩子方法,默认返回 true,子类可以选择性地进行覆盖
    protected boolean hookMethod() {
        return true;
    }
    // 钩子方法,可选实现,子类可以选择性地进行覆盖
    protected void operation3() {
        // 具体实现
    }
}

image.gif

然后,我们创建具体的子类来实现抽象类中的具体操作方法:

 

public class ConcreteClass extends AbstractClass {
    @Override
    protected void operation1() {
        System.out.println("ConcreteClass: operation1");
    }
    @Override
    protected void operation2() {
        System.out.println("ConcreteClass: operation2");
    }
    @Override
    protected boolean hookMethod() {
        return false;
    }
}

image.gif

最后,我们可以通过调用模板方法来使用抽象类和具体子类:

public class Client {
    public static void main(String[] args) {
        AbstractClass abstractClass = new ConcreteClass();
        abstractClass.templateMethod();
    }
}

image.gif


在上述示例中,我们定义了一个抽象类 AbstractClass,其中包含了一个模板方法 templateMethod,以及一些基本操作方法和钩子方法。具体的子类 ConcreteClass 继承了抽象类,并实现了基本操作方法和钩子方法。

在客户端中,我们创建了一个具体子类对象,并调用其模板方法 templateMethod。在运行时,模板方法会按照预定义的顺序依次调用基本操作方法和钩子方法。

需要注意的是,模板方法模式将通用的算法逻辑放在抽象类中,而具体的实现细节由子类来完成。这样可以提高代码的可复用性和可扩展性,同时也将算法的变化封装在子类中,使得子类可以更自由地进行扩展和变化。

四,策略模式

1.介绍

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装在独立的策略类中,使得它们可以互相替换。通过使用策略模式,可以使得算法的变化独立于使用算法的客户端。

这种模式属于对象行为型模式。

2.代码示例

下面是一个示例的 Java 实现:

首先,我们定义一个策略接口,其中包含了算法的抽象方法:

public interface Strategy {
    void execute();
}

image.gif

然后,我们创建具体的策略类来实现策略接口中的算法方法:

 

public class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行策略A");
    }
}
public class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行策略B");
    }
}
public class ConcreteStrategyC implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行策略C");
    }
}

image.gif

接下来,我们定义一个上下文类,用于维护对策略对象的引用,并调用其执行算法的方法:

 

public class Context {
    private Strategy strategy;
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    public void executeStrategy() {
        strategy.execute();
    }
}

image.gif

最后,我们可以通过创建具体的策略对象,并使用上下文来实现不同的算法策略:

public class Client {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStrategyA());
        context.executeStrategy();
        context.setStrategy(new ConcreteStrategyB());
        context.executeStrategy();
        context.setStrategy(new ConcreteStrategyC());
        context.executeStrategy();
    }
}

image.gif

在上述示例中,我们定义了一个策略接口 Strategy,其中包含了执行算法的抽象方法 execute。然后,我们创建了多个具体的策略类 ConcreteStrategyA、ConcreteStrategyB 和 ConcreteStrategyC,分别实现了不同的算法。

在客户端中,我们创建了一个上下文对象 Context,并设置不同的策略对象。通过调用上下文的 executeStrategy 方法,可以根据不同的策略执行对应的算法。

策略模式通过将算法封装在独立的策略类中,使得它们可以独立变化和互相替换。这样可以提高代码的灵活性和可维护性,同时也将算法的变化从客户端代码中解耦出来,使得客户端可以更加专注于业务逻辑。

四,状态模式

1.介绍

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态发生改变时改变它的行为。通过使用状态模式,可以将一个对象的状态从其行为中分离出来,使得对象可以根据状态来改变其行为。

这种模式属于对象行为型模式。

2.代码示例

下面是一个示例的 Java 实现:

首先,我们定义一个状态接口,其中包含了状态对应的操作方法:

public interface State {
    void handle();
}

image.gif

然后,我们创建多个具体的状态类,实现不同状态下的操作方法:

 

public class ConcreteStateA implements State {
    @Override
    public void handle() {
        System.out.println("当前状态为 A");
    }
}
public class ConcreteStateB implements State {
    @Override
    public void handle() {
        System.out.println("当前状态为 B");
    }
}
public class ConcreteStateC implements State {
    @Override
    public void handle() {
        System.out.println("当前状态为 C");
    }
}

image.gif

接下来,我们定义一个上下文类,用于维护当前状态,并根据不同状态自动切换对应的状态:

 

public class Context {
    private State currentState;
    public Context() {
        this.currentState = new ConcreteStateA();
    }
    public void setCurrentState(State currentState) {
        this.currentState = currentState;
    }
    public void handle() {
        currentState.handle();
        if (currentState instanceof ConcreteStateA) {
            setCurrentState(new ConcreteStateB());
        } else if (currentState instanceof ConcreteStateB) {
            setCurrentState(new ConcreteStateC());
        } else if (currentState instanceof ConcreteStateC) {
            setCurrentState(new ConcreteStateA());
        }
    }
}

image.gif

最后,我们可以通过创建上下文对象,并反复调用其 handle 方法来实现不同状态下的不同行为:

public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.handle();
        context.handle();
        context.handle();
    }
}

image.gif

在上述示例中,我们定义了一个状态接口 State,其中包含了不同状态下对应的操作方法。然后,我们创建了多个具体的状态类 ConcreteStateA、ConcreteStateB 和 ConcreteStateC,实现了不同状态下的不同操作。

在上下文类 Context 中,我们维护了当前状态 currentState,并根据不同状态自动切换到对应的状态。在客户端中,我们创建了一个上下文对象,并反复调用其 handle 方法,从而实现不同状态下的不同行为。

状态模式通过将状态封装在独立的状态类中,使得状态可以独立变化和互相替换。这样可以提高代码的灵活性和可维护性,同时也将状态的变化从客户端代码中解耦出来,使得客户端可以更加专注于业务逻辑。

五,观察者模式

1.介绍

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,其中一个对象(称为主题或可观察者)状态发生变化时会自动通知其他依赖该对象的对象(称为观察者),使得观察者可以更新自己的状态。

这种模式属于对象行为型模式。

2.代码示例

下面是一个示例的 Java 实现:

首先,我们定义一个主题接口,其中包含了添加、删除和通知观察者的方法:

public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

image.gif

然后,我们创建一个具体的主题类,实现主题接口的方法,并维护观察者列表:

 

import java.util.ArrayList;
import java.util.List;
public class ConcreteSubject implements Subject {
    private List<Observer> observers;
    public ConcreteSubject() {
        this.observers = new ArrayList<>();
    }
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

image.gif

接下来,我们定义一个观察者接口,其中包含了更新自身状态的方法:

import java.util.ArrayList;
import java.util.List;
public class ConcreteSubject implements Subject {
    private List<Observer> observers;
    public ConcreteSubject() {
        this.observers = new ArrayList<>();
    }
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

image.gif

然后,我们创建多个具体的观察者类,实现观察者接口的方法:

 

public class ConcreteObserverA implements Observer {
    @Override
    public void update() {
        System.out.println("观察者 A 收到通知,开始更新自身状态");
    }
}
public class ConcreteObserverB implements Observer {
    @Override
    public void update() {
        System.out.println("观察者 B 收到通知,开始更新自身状态");
    }
}

image.gif

最后,我们可以创建主题和观察者对象,并通过添加观察者、主题改变状态来验证观察者模式的工作方式:

 

public class Client {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Observer observerA = new ConcreteObserverA();
        Observer observerB = new ConcreteObserverB();
        subject.addObserver(observerA);
        subject.addObserver(observerB);
        // 主题改变状态时,通知所有观察者
        subject.notifyObservers();
    }
}

image.gif

在上述示例中,我们定义了一个主题接口 Subject,其中包含了添加、删除和通知观察者的方法。然后,我们创建了一个具体的主题类 ConcreteSubject,实现了主题接口的方法,并维护了观察者列表。在通知观察者时,遍历观察者列表并调用其 update 方法。

我们还定义了一个观察者接口 Observer,其中包含了更新自身状态的方法。然后,我们创建了多个具体的观察者类 ConcreteObserverA 和 ConcreteObserverB,实现了观察者接口的方法。

在客户端中,我们创建了一个主题对象和多个观察者对象。通过调用主题的添加观察者、通知观察者的方法,可以实现主题状态变化时触发观察者的更新。

观察者模式使得主题和观察者之间的耦合度降低,同时也支持动态添加和删除观察者。这样可以提高代码的灵活性和可维护性,使得主题和观察者可以独立变化。

六,备忘录模式

1.介绍

备忘录模式(Memento Pattern)是一种行为型设计模式,它允许你保存和恢复一个对象的内部状态,而不会破坏其封装性。备忘录有三个角色:原始对象、备忘录和负责人。

2.代码示例

下面是一个示例的 Java 实现:

首先,我们定义一个备忘录类 Memento,用于存储原始对象的内部状态:

 

public class Memento {
    private String state;
    public Memento(String state) {
        this.state = state;
    }
    public String getState() {
        return state;
    }
}

image.gif

然后,我们创建一个原始对象类 OriginalObject,它维护了当前状态,并实现了创建备忘录和恢复备忘录的方法:

 

public class OriginalObject {
    private String state;
    public OriginalObject(String state) {
        this.state = state;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    public Memento createMemento() {
        return new Memento(state);
    }
    public void restoreMemento(Memento memento) {
        state = memento.getState();
    }
}

image.gif

我们还需要一个负责人类 Caretaker,用于管理备忘录的存储和恢复:

 

import java.util.ArrayList;
import java.util.List;
public class Caretaker {
    private List<Memento> mementos = new ArrayList<>();
    public void addMemento(Memento memento) {
        mementos.add(memento);
    }
    public Memento getMemento(int index) {
        return mementos.get(index);
    }
}

image.gif

最后,我们可以创建一个客户端类 Client,通过调用原始对象的 setState、createMemento 和 restoreMemento 方法来验证备忘录模式的工作方式:

 

public class Client {
    public static void main(String[] args) {
        OriginalObject originalObject = new OriginalObject("state 1");
        System.out.println("初始状态:" + originalObject.getState());
        Caretaker caretaker = new Caretaker();
        // 存储当前状态
        caretaker.addMemento(originalObject.createMemento());
        // 改变状态
        originalObject.setState("state 2");
        System.out.println("改变后状态:" + originalObject.getState());
        // 存储新状态
        caretaker.addMemento(originalObject.createMemento());
        // 再次改变状态
        originalObject.setState("state 3");
        System.out.println("再次改变后状态:" + originalObject.getState());
        // 恢复到之前的状态
        originalObject.restoreMemento(caretaker.getMemento(1));
        System.out.println("恢复后状态:" + originalObject.getState());
    }
}

image.gif

在上述示例中,我们创建了一个备忘录类 Memento 用于存储原始对象的内部状态。然后,我们创建了一个原始对象类 OriginalObject,它维护了当前状态,并实现了创建备忘录和恢复备忘录的方法。

我们还创建了一个负责人类 Caretaker,用于管理备忘录的存储和恢复。

在客户端中,我们首先创建了一个原始对象 originalObject,并通过其 setState 和 restoreMemento 方法改变和恢复状态。在改变状态时,我们使用 createMemento 方法创建备忘录并存储到负责人类 caretaker 中,在恢复状态时从负责人类中获取备忘录并通过 restoreMemento 方法恢复状态。

备忘录模式可以实现对象的状态保存和恢复,而不破坏其封装性。它使得类的接口不会因为保存内部状态而失效,同时也保证了状态的安全性和一致性。

七,中介这模式

1.介绍

中介者模式(Mediator Pattern)是一种行为型设计模式,它能够减少对象之间的依赖关系,使得对象不需要显示地相互引用,从而使耦合性降低,系统易于扩展。

2.代码示例

中介者模式由以下几个角色组成:

- 中介者(Mediator):定义了各个具体同事类之间通信的接口和方法。

- 具体中介者(Concrete Mediator):实现了中介者接口,负责协调各个具体同事类之间的交互关系。

- 同事类(Colleague):每个同事类都含有一个指向中介者的引用,并通过中介者来与其他同事类通信。同事类有两种类型:

 - 抽象同事类(Abstract Colleague):抽象同事类定义了同事类之间通信所需的基本方法。

 - 具体同事类(Concrete Colleague):具体同事类是抽象同事类的子类,具体实现了在同事类之间通信所需的基本方法。下面是一个 Java 示例代码:

 

// 抽象同事类
abstract class Colleague {
    protected Mediator mediator;
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    // 发送信息
    abstract void send(String message);
    // 接收信息
    abstract void receive(String message);
}
// 具体同事类 1
class ConcreteColleague1 extends Colleague {
    public ConcreteColleague1(Mediator mediator) {
        super(mediator);
    }
    @Override
    void send(String message) {
        mediator.send(message, this);
    }
    @Override
    void receive(String message) {
        System.out.println("ConcreteColleague1 received: " + message);
    }
}
// 具体同事类 2
class ConcreteColleague2 extends Colleague {
    public ConcreteColleague2(Mediator mediator) {
        super(mediator);
    }
    @Override
    void send(String message) {
        mediator.send(message, this);
    }
    @Override
    void receive(String message) {
        System.out.println("ConcreteColleague2 received: " + message);
    }
}
// 抽象中介者
interface Mediator {
    void send(String message, Colleague sender);
}
// 具体中介者
class ConcreteMediator implements Mediator {
    private ConcreteColleague1 colleague1;
    private ConcreteColleague2 colleague2;
    public void setColleague1(ConcreteColleague1 colleague1) {
        this.colleague1 = colleague1;
    }
    public void setColleague2(ConcreteColleague2 colleague2) {
        this.colleague2 = colleague2;
    }
    @Override
    public void send(String message, Colleague sender) {
        if (sender == colleague1) {
            colleague2.receive(message);
        } else {
            colleague1.receive(message);
        }
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();
        ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
        ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator);
        mediator.setColleague1(colleague1);
        mediator.setColleague2(colleague2);
        colleague1.send("Hello, how are you?");
        colleague2.send("Fine, thank you. And you?");
    }
}

image.gif

在上述示例中,我们定义了抽象同事类 Colleague 带有 Mediator 属性的抽象方法 send 和 receive,用于发送和接收信息。

我们还定义了具体同事类 ConcreteColleague1 和 ConcreteColleague2 继承自抽象同事类 Colleague,并实现其 send 和 receive 方法。

接着,我们定义了中介者接口 Mediator,其中 send 方法用于发送信息。

最后,我们定义了具体中介者 ConcreteMediator 对象,并将其与两个具体同事类联系起来。在客户端代码中,我们通过调用具体同事类的 send 方法来发送消息,然后通过抽象中介者接口 Mediator 的实现类 ConcreteMediator 来协调这些消息的传递。

总的来说,中介者模式可以使对象之间的依赖关系变得简单,并且能够避免对象之间的直接依赖,从而使得对象更加松散耦合。

八,迭代器模式

1.介绍

迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种访问聚合对象(如列表、集合)中元素的统一方式,而无需暴露该对象的内部表示。

2.代码示例

迭代器模式由以下几个角色组成:

- 迭代器(Iterator):定义了访问和遍历聚合对象元素的接口。

- 具体迭代器(ConcreteIterator):实现了迭代器接口,具体实现遍历聚合对象的方法。

- 聚合对象(Aggregate):定义了创建迭代器的接口。

- 具体聚合对象(ConcreteAggregate):实现了聚合对象接口,具体实现创建迭代器的方法。下面是一个 Java 示例代码:

 

// 迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}
// 聚合对象接口
interface Aggregate {
    Iterator createIterator();
}
// 具体迭代器
class ConcreteIterator implements Iterator {
    private Object[] elements;
    private int position = 0;
    public ConcreteIterator(Object[] elements) {
        this.elements = elements;
    }
    @Override
    public boolean hasNext() {
        return position < elements.length;
    }
    @Override
    public Object next() {
        if (hasNext()) {
            return elements[position++];
        }
        return null;
    }
}
// 具体聚合对象
class ConcreteAggregate implements Aggregate {
    private Object[] elements;
    public ConcreteAggregate(Object[] elements) {
        this.elements = elements;
    }
    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(elements);
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        Object[] elements = { "A", "B", "C", "D", "E" };
        ConcreteAggregate aggregate = new ConcreteAggregate(elements);
        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            Object element = iterator.next();
            System.out.println(element);
        }
    }
}

image.gif

在上述示例中,我们定义了迭代器接口 Iterator,其中 hasNext 方法用于判断是否还有下一个元素,next 方法用于获取下一个元素。

然后,我们定义了聚合对象接口 Aggregate,其中 createIterator 方法用于创建迭代器。

接着,我们实现了具体的迭代器 ConcreteIterator,它使用一个数组来保存聚合对象的元素,并实现了迭代器接口的 hasNext 和 next 方法。

然后,我们实现了具体的聚合对象 ConcreteAggregate,它使用一个数组来保存元素,并实现了聚合对象接口的 createIterator 方法,该方法返回一个具体迭代器对象。

最后,在客户端代码中,我们创建了一个具体聚合对象 ConcreteAggregate,并调用其 createIterator 方法来获得一个迭代器对象。通过迭代器的 hasNext 和 next 方法,我们可以遍历聚合对象中的元素并进行操作。

总的来说,迭代器模式提供了一种统一的方式来访问聚合对象中的元素,无需暴露聚合对象的内部表示。这样可以让客户端代码与具体的聚合对象解耦,并且使得聚合对象的内部结构发生变化时,客户端代码不需要做出修改。

九,解析器模式

1.介绍

解释器模式(Interpreter Pattern)是一种行为型设计模式,它用于解释和执行特定语言的语法或表达式。该模式通过定义一个语言文法,并使用解释器来解释该语言的表达式,从而进行相应的操作。

2.代码示例

解释器模式包含以下几个角色:

- 抽象表达式(Abstract Expression):定义了解释器的接口,声明了解释操作的抽象方法。

- 终结符表达式(Terminal Expression):实现了抽象表达式接口,并提供了实际的解释操作。

- 非终结符表达式(Non-terminal Expression):实现了抽象表达式接口,并根据需要递归调用其他表达式的解释操作。

- 上下文(Context):包含解释器解释的上下文信息。

下面是一个 Java 示例代码,演示如何使用解释器模式解析简单的四则运算表达式:

// 抽象表达式
interface Expression {
    int interpret(Context context);
}
// 终结符表达式
class NumberExpression implements Expression {
    private int number;
    public NumberExpression(int number) {
        this.number = number;
    }
    @Override
    public int interpret(Context context) {
        return number;
    }
}
// 非终结符表达式 - 加法
class AddExpression implements Expression {
    private Expression leftExpression;
    private Expression rightExpression;
    public AddExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }
    @Override
    public int interpret(Context context) {
        return leftExpression.interpret(context) + rightExpression.interpret(context);
    }
}
// 上下文
class Context {
    private String expression;
    public Context(String expression) {
        this.expression = expression;
    }
    public String getExpression() {
        return expression;
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 构建解析树
        Expression expression = buildExpression();
        // 创建上下文
        Context context = new Context("5 2 3 + *");
        // 解释表达式
        int result = expression.interpret(context);
        System.out.println("解释器计算结果: " + result);
    }
    public static Expression buildExpression() {
        // 构建解析树:5 * (2 + 3)
        Expression number1 = new NumberExpression(5);
        Expression number2 = new NumberExpression(2);
        Expression number3 = new NumberExpression(3);
        Expression addition = new AddExpression(number2, number3);
        Expression multiplication = new AddExpression(number1, addition);
        return multiplication;
    }
}

image.gif

 

在上述示例中,我们首先定义了抽象表达式接口 Expression,其中声明了 interpret 方法用于解释操作。

然后,我们实现了终结符表达式 NumberExpression,它表示一个数字,并且 interpret 方法返回该数字的值。

接着,我们实现了非终结符表达式 AddExpression,它表示加法操作。在 interpret 方法中,我们递归调用左右子表达式的 interpret 方法,并进行求和操作。

然后,我们定义了上下文类 Context,它包含了需要解释的表达式。

最后,在客户端代码中,我们构建了一个解析树,并传入一个特定的表达式给上下文对象。通过调用解释器的 interpret 方法,我们可以解释并执行该表达式,得到结果。

总的来说,解释器模式可以用于解析和执行特定语言的语法或表达式。它通过定义抽象表达式和具体表达式来实现解释操作,并使用上下文对象提供解释所需的信息。这样可以将复杂的语言解析过程分解成简单的解释器,提供了更好的可扩展性和灵活性。

十,命令模式

1.介绍

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,使得可以用不同的请求对客户进行参数化,并且能够将请求排队或记录请求日志,以及支持可撤销的操作。

2.代码示例

命令模式包含以下几个角色:

- 命令接口(Command):定义了执行命令的方法。

- 具体命令(Concrete Command):实现了命令接口,并且持有接收者对象和执行命令的方法。

- 接收者(Receiver):负责执行具体的业务逻辑。

- 调用者(Invoker):负责调用命令对象执行相应的操作。

- 客户端(Client):创建命令对象并设置接收者,然后调用 Invoker 执行命令。

下面是一个使用 Java 实现的命令模式示例代码:

 

// 命令接口
public interface Command {
    void execute();
}
// 具体命令 - 开机命令
public class TurnOnCommand implements Command {
    private Receiver receiver;
    public TurnOnCommand(Receiver receiver) {
        this.receiver = receiver;
    }
    @Override
    public void execute() {
        receiver.turnOn();
    }
}
// 具体命令 - 关机命令
public class TurnOffCommand implements Command {
    private Receiver receiver;
    public TurnOffCommand(Receiver receiver) {
        this.receiver = receiver;
    }
    @Override
    public void execute() {
        receiver.turnOff();
    }
}
// 接收者
public class Receiver {
    public void turnOn() {
        System.out.println("电视机已经开机了");
    }
    public void turnOff() {
        System.out.println("电视机已经关机了");
    }
}
// 调用者
public class Invoker {
    private Command command;
    public void setCommand(Command command) {
        this.command = command;
    }
    public void executeCommand() {
        command.execute();
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建接收者对象
        Receiver receiver = new Receiver();
        // 创建具体命令对象并设置接收者
        Command onCommand = new TurnOnCommand(receiver);
        Command offCommand = new TurnOffCommand(receiver);
        // 创建调用者对象并设置命令
        Invoker invoker = new Invoker();
        invoker.setCommand(onCommand);
        invoker.executeCommand();
        // 切换命令对象并执行
        invoker.setCommand(offCommand);
        invoker.executeCommand();
    }
}

image.gif

在上述示例中,我们定义了一个命令接口 Command,其中包含了执行命令的方法 execute。

然后,我们实现了具体命令 TurnOnCommand 和 TurnOffCommand,它们分别负责执行开机和关机的业务逻辑。这些具体命令持有了接收者 Receiver 的引用,并在 execute 方法中调用了接收者的相应方法。

接着,我们创建了一个接收者 Receiver,它负责执行具体的业务逻辑。

然后,我们实现了调用者 Invoker,它持有一个命令对象,并且可以执行命令。

最后,在客户端代码中,我们创建了接收者对象和具体命令对象,并将接收者对象注入到具体命令中。然后,我们创建调用者对象并设置命令,最后执行命令即可。

总的来说,命令模式将请求封装成对象,从而使得可以用不同的请求对客户端进行参数化,并且能够将请求排队或记录请求日志,并且支持可撤销的操作。这样可以减少系统的耦合度,并且提高系统的可扩展性和灵活性。

十一,责任链模式

1.介绍

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它通过将请求发送者和接收者解耦,从而使得多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

在责任链模式中,通常将每个处理者看作一个链表中的节点,每个节点都包含了处理请求的方法以及后继节点的引用。当请求来临时,它会首先被送到链表的第一个节点进行处理;如果这个节点不能处理它,那么该请求就会被转发给链表中的下一个节点,直到有一个节点能够处理它为止。在实际应用中,可以根据需要动态地增加或删除节点,从而灵活地定制处理链。

2.代码示例

下面是一个使用 Java 实现的责任链模式示例代码:

// 抽象处理者 - 审批人
public abstract class Approver {
    protected String name; // 审批人姓名
    protected Approver next; // 后继审批人
    public Approver(String name) {
        this.name = name;
    }
    // 处理请求的抽象方法
    public abstract void processRequest(PurchaseRequest request);
    // 设置后继审批人
    public void setNext(Approver approver) {
        this.next = approver;
    }
}
// 具体处理者 - 主任
public class Director extends Approver {
    public Director(String name) {
        super(name);
    }
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= 5000) {
            System.out.println("主任 " + name + " 审批采购单:" + request);
        } else {
            // 转发请求给后继者
            next.processRequest(request);
        }
    }
}
// 具体处理者 - 经理
public class Manager extends Approver {
    public Manager(String name) {
        super(name);
    }
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= 10000) {
            System.out.println("经理 " + name + " 审批采购单:" + request);
        } else {
            // 转发请求给后继者
            next.processRequest(request);
        }
    }
}
// 具体处理者 - 总经理
public class GeneralManager extends Approver {
    public GeneralManager(String name) {
        super(name);
    }
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= 50000) {
            System.out.println("总经理 " + name + " 审批采购单:" + request);
        } else {
            System.out.println("采购单金额太大," + name + " 没有审批权限");
        }
    }
}
// 请求类
public class PurchaseRequest {
    private String name; // 采购物品名称
    private double amount; // 采购金额
    public PurchaseRequest(String name, double amount) {
        this.name = name;
        this.amount = amount;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getAmount() {
        return amount;
    }
    public void setAmount(double amount) {
        this.amount = amount;
    }
    @Override
    public String toString() {
        return "PurchaseRequest{" +
                "name='" + name + '\'' +
                ", amount=" + amount +
                '}';
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建审批链
        Approver director = new Director("张三");
        Approver manager = new Manager("李四");
        Approver generalManager = new GeneralManager("王五");
        director.setNext(manager);
        manager.setNext(generalManager);
        // 处理请求
        PurchaseRequest request1 = new PurchaseRequest("办公用品", 3000);
        director.processRequest(request1);
        PurchaseRequest request2 = new PurchaseRequest("办公电脑", 10000);
        director.processRequest(request2);
        PurchaseRequest request3 = new PurchaseRequest("办公家具", 50000);
        director.processRequest(request3);
    }
}

image.gif

在上述示例中,我们通过定义一个抽象处理者类 Approver,它包含了处理请求的抽象方法和后继节点的引用。然后,我们定义了三个具体处理者类:主任、经理和总经理,它们分别实现了处理请求的方法,处理完请求之后,如果有后继节点,就将请求转发给它;否则,直接返回。

在客户端代码中,我们创建了一个审批链,并将请求依次发送给处理者进行处理。如果某个处理者不能处理请求,就将请求转发给它的后继节点,直到有一个处理者能够处理它为止。

总的来说,责任链模式通过将请求发送者和接收者解耦,从而使得多个对象都有机会处理这个请求。在实际应用中,可以根据需要动态地增加或删除节点,从而灵活地定制处理链。

目录
相关文章
|
5天前
|
Java 索引
String字符串常用函数以及示例 JAVA基础
String字符串常用函数以及示例 JAVA基础
|
5天前
|
设计模式 算法 Java
Java一分钟之-设计模式:策略模式与模板方法
【5月更文挑战第17天】本文介绍了策略模式和模板方法模式,两种行为设计模式用于处理算法变化和代码复用。策略模式封装不同算法,允许客户独立于具体策略进行选择,但需注意选择复杂度和过度设计。模板方法模式定义算法骨架,延迟部分步骤给子类实现,但过度抽象或滥用继承可能导致问题。代码示例展示了两种模式的应用。根据场景选择合适模式,以保持代码清晰和可维护。
10 1
|
5天前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
19 1
|
5天前
|
设计模式 Java
Java一分钟之-设计模式:工厂模式与抽象工厂模式
【5月更文挑战第17天】本文探讨了软件工程中的两种创建型设计模式——工厂模式和抽象工厂模式。工厂模式提供了一个创建对象的接口,延迟实例化到子类决定。过度使用或违反单一职责原则可能导致问题。代码示例展示了如何创建形状的工厂。抽象工厂模式则用于创建一系列相关对象,而不指定具体类,但添加新产品可能需修改现有工厂。代码示例展示了创建颜色和形状的工厂。根据需求选择模式,注意灵活性和耦合度。理解并恰当运用这些模式能提升代码质量。
16 2
|
5天前
|
设计模式 Java
Java一分钟之-设计模式:观察者模式与事件驱动
【5月更文挑战第17天】本文探讨了Java中实现组件间通信的观察者模式和事件驱动编程。观察者模式提供订阅机制,当对象状态改变时通知所有依赖对象。然而,它可能引发性能问题、循环依赖和内存泄漏。代码示例展示了如何实现和避免这些问题。事件驱动编程则响应用户输入和系统事件,但回调地狱和同步/异步混淆可能造成困扰。JavaFX事件驱动示例解释了如何处理事件。理解这两种模式有助于编写健壮的程序。
10 1
|
5天前
|
设计模式 SQL 安全
Java一分钟之-设计模式:单例模式的实现
【5月更文挑战第16天】本文介绍了单例模式的四种实现方式:饿汉式(静态初始化)、懒汉式(双检锁)、静态内部类和枚举单例,以及相关问题和解决方法。关注线程安全、反射攻击、序列化、生命周期和测试性,选择合适的实现方式以确保代码质量。了解单例模式的优缺点,谨慎使用,提升设计效率。
22 3
|
6天前
|
设计模式 Java
【JAVA基础篇教学】第十四篇:Java中设计模式
【JAVA基础篇教学】第十四篇:Java中设计模式
|
6天前
|
设计模式 算法 Java
设计模式在Java开发中的应用
设计模式在Java开发中的应用
18 0
|
6天前
|
设计模式 API
【设计模式】适配器和桥接器模式有什么区别
【设计模式】适配器和桥接器模式有什么区别
10 1
|
6天前
|
设计模式
【设计模式】张一鸣笔记:责任链接模式怎么用?
【设计模式】张一鸣笔记:责任链接模式怎么用?
11 1