Java面向对象设计模式学习(六):行为型模式(责任链、状态、观察者、中介者)

本文主要介绍Java面向对象23种设计模式中行为型模式中的部分设计模式,上接Java面向对象设计模式学习(五)

四、责任链模式

责任链模式,也称职责链模式,主要面向以下问题:一个请求多个对象可以处理,但每个对象的处理条件或权限不同

责任链模式是指:为了避免请求发送者多个请求处理者耦合在一起,将所有请求处理者通过前一对象记住其下一个对象引用成一条;当有请求发生时,可将请求沿着这条链传递直到有对象处理它为止。 

该模式下客户只需要将请求发送责任链上即可,无须关心请求的处理细节和请求的传递过程,实现了请求发送与处理的解耦。

责任链模式主要角色如下:

  1. 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接
  2. 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  3. 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

 

责任链请求处理流程图如下:

按照结构图实现的实例代码如下:

//抽象处理者角色
abstract class Handler{
    private Handler next;

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }

    //处理请求的方法
    public abstract void handleRequest(String request);
}
//具体处理者角色1
class ConcreteHandler1 extends Handler{
    public void handleRequest(String request){
        if(request.equals("one")){
            System.out.println("具体处理者1负责该请求处理");
        }else {
            if(getNext()!=null){
                getNext().handleRequest(request);
            }else {
                System.out.println("该请求无对应处理者");
            }
        }
    }
}
//具体处理者角色2
class ConcreteHandler2 extends Handler{
    public void handleRequest(String request){
        if(request.equals("two")){
            System.out.println("具体处理者2负责该请求处理");
        }else {
            if(getNext()!=null){
                getNext().handleRequest(request);
            }else {
                System.out.println("该请求无对应处理者");
            }
        }
    }
}

public class ChainOfResponsibilityPattern{
    public static void main(String[] args) {
        //组装职责链
        Handler handler1=new ConcreteHandler1();
        Handler handler2=new ConcreteHandler2();
        handler1.setNext(handler2);
        //提交请求
        handler1.handleRequest("two");
    }
}

程序输出结果如下:

具体处理者2负责该请求处理

责任链应用实例:

假定某银行贷款审批规则如下 :小于10万窗口可直接审批;10-100万需经理审批;100-300万需行长审批;大于300万不予审批。则上述规则适合责任链模式实现。定义一个领导类(Leader),它是抽象处理者包含了一个指向下一位领导的指针 next 和一个处理的抽象处理方法 handleRequest(int LeaveDays);然后,定义窗口类(Clerk)、经理类(Manager)和行长类(President),它们是抽象处理者的子类,是具体处理者,必须根据自己的权力去实现父类的 handleRequest(int mount) 方法,如果无权处理就将请求交给下一位具体处理者,直到最后;客户类负责创建处理链,并将数额交给链头的具体处理者(窗口)。

具体代码如下:


//抽象处理者
abstract class Leader{
    private Leader next;

    public Leader getNext() {
        return next;
    }

    public void setNext(Leader next) {
        this.next = next;
    }
    //请求处理方法
    public abstract void handleRequest(int mount);
}
//具体处理类:窗口
class Clerk extends Leader{
    @Override
    public void handleRequest(int mount) {
        if(mount<=10){
            System.out.println("您申请的"+mount+"万贷款已由窗口审批通过");
        }else {
            if(getNext()!=null){
                getNext().handleRequest(mount);
            }else {
                System.out.println("贷款超额,暂时无法审批");
            }
        }
    }
}
//具体处理类:经理
class Manager extends Leader{
    @Override
    public void handleRequest(int mount) {
        if(mount<=100&&mount>10){
            System.out.println("您申请的"+mount+"万贷款已由窗口审批通过");
        }else {
            if(getNext()!=null){
                getNext().handleRequest(mount);
            }else {
                System.out.println("贷款超额,暂时无法审批");
            }
        }
    }
}
//具体处理类:行长
class President extends Leader{
    @Override
    public void handleRequest(int mount) {
        if(mount<=300&&mount>100){
            System.out.println("您申请的"+mount+"万贷款已由窗口审批通过");
        }else {
            if(getNext()!=null){
                getNext().handleRequest(mount);
            }else {
                System.out.println("贷款超额,暂时无法审批");
            }
        }
    }
}

public class LoanApprovalTest
{
    public static void main(String[] args)
    {
        //组装责任链
        Leader leader1=new Clerk();
        Leader leader2=new Manager();
        Leader leader3=new President();
        leader1.setNext(leader2);
        leader2.setNext(leader3);
        //提交请求
        leader1.handleRequest(210);
    }
}

程序输出结果如下:

您申请的210万贷款已由窗口审批通过

如果后续需要增加一个总行经理类,可以审批300-500万贷款数额,只需要创建继承类后在职责链最后setNext(new HigherManager()) 即可,从而便于程序扩展。

五、状态模式

状态模式面向的问题是:应用程序中的有些对象可能会根据不同情况做出不同行为,我们把影响对象行为的一个或多个动态变化属性称为状态。当有状态的对象与外部事件产生互动时,其内部状态会发生改变,从而使得其行为也随之发生改变。传统解决方式是使用if-else语句对所有情况进行判断处理,违背了“开闭原则”,难以进行扩展。

状态模式的解决思想是:当控制一个对象状态转换条件表达式过于复杂时,把相关“判断逻辑提取出来,放到一系列的状态类当中,这样可以把原来复杂的逻辑判断简单化。

状态模式的主要角色如下:

  1. 环境(Context)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关操作委托当前状态对象来处理。
  2. 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
  3. 具体状态(Concrete    State)角色:实现抽象状态所对应的行为。

 

以上结构对应的实例代码如下:

//环境类
class Context{
    private State state;
    //定义环境类的初始状态
    public Context(){
        this.state=new ConcreteStateA();
    }
    //读取状态
    public State getState() {
        return state;
    }
    //设置新状态
    public void setState(State state) {
        this.state = state;
    }
    //对请求做处理
    public void Handle(){
        state.Handle(this);
    }
}

//抽象状态类
abstract class State{
    public abstract void Handle(Context context);
}
//具体状态A类
class ConcreteStateA extends State{
    public void Handle(Context context){
        System.out.println("当前状态为 A.");
        context.setState(new ConcreteStateB());
    }
}
//具体状态B类
class ConcreteStateB extends State{
    public void Handle(Context context){
        System.out.println("当前状态为 B.");
        context.setState(new ConcreteStateA());
    }
}

public class StatePatternClient
{
    public static void main(String[] args)
    {
        Context context=new Context();    //创建环境
        context.Handle();    //处理请求
        context.Handle();
    }
}

程序输出结果如下:

当前状态为 A.
当前状态为 B.

六、观察者模式

 观察者模式,又称发布-订阅模式,是指多个对象间存在一对多依赖关系,当一个对象状态发生改变时,所有依赖于它的对象得到通知并被自动更新

观察者模式的主要角色如下:

  1. 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  2. 具体主题(Concrete    Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  3. 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

以上结构对应的实例代码如下:

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

//抽象目标
abstract class Subject{
    protected List<Observer> observers=new ArrayList<Observer>();
    //增加观察者方法
    public void add(Observer observer){
        observers.add(observer);
    }
    //删除观察者方法
    public void remove(Observer observer){
        observers.remove(observer);
    }
    public abstract void notifyObserver();//通知观察者方法
}
//具体目标:实现通知
class ConcreteSubject extends Subject{
    public void notifyObserver(){
        System.out.println("具体目标改变");
        System.out.println("---------");

        for (Observer observer : observers) {
            ((Observer)observer).response();
        }
    }
}

//抽象观察者
interface Observer{
    void response();//反应
}
//具体观察者1
class ConcreteObserver1 implements Observer{
    public void response(){
        System.out.println("具体观察者1收到");
    }
}
//具体观察者2
class ConcreteObserver2 implements Observer{
    public void response(){
        System.out.println("具体观察者2收到");
    }
}

public class ObserverPattern{
    public static void main(String[] args) {
        Subject subject=new ConcreteSubject();
        Observer observer1=new ConcreteObserver1();
        Observer observer2=new ConcreteObserver2();
        subject.add(observer1);
        subject.add(observer2);
        subject.notifyObserver();
    }
}

 程序输出结果如下:

具体目标改变
---------
具体观察者1收到
具体观察者2收到

七、中介者模式

 中介者模式旨在解决对象之间存在如“网状结构”的复杂关系,是指定义一个中介对象封装一系列对象之间交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。常见的使用如MVC 框架中,控制器(C)就是模型(M)和视图(V)的中介者;QQ 聊天程序的“中介者”是 QQ 服务器等。

中介者模式的关键是找出中介者 ,模式主要角色如下:

  1. 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册转发同事对象信息的抽象方法。
  2. 具体中介者(ConcreteMediator)角色:实现中介者接口定义一个 List管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
  3. 抽象同事类(Colleague)角色:定义同事的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
  4. 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。

结构图实例代码略,直接进入应用实例。

中介者模式应用实例:

假定存在一个“房产中介”,可以为“卖方”与“买方”提供房产信息交流平台,则适合使用中介者模式解决。

首先定义中介公司(Medium)接口,它是抽象中介者,包含客户注册方法 register(Customer member) 和信息转发方法 relay(String from,String ad);再定义一个具体房地产中介(EstateMedium)公司,它是具体中介者类,它包含了保存客户信息的 List 对象,并实现了中介公司中的抽象方法。

然后定义一个客户(Qistomer)类,它是抽象同事类,其中包含了中介者的对象,和发送信息的 send(String ad) 方法与接收信息的 receive(String from,Stringad) 方法的接口。

最后定义卖方(Seller)类和买方(Buyer)类,它们是具体同事类,是客户(Customer)类的子类,它们实现了父类中的抽象方法,通过中介者类进行信息交流。

程序实例代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

//抽象中介者:中介公司
interface Medium{
    void register(Customer member);//客户注册
    void relay(String from,String ad);//转发
}
//具体中介者:房产中介
class EstateMedium implements Medium{
    private List<Customer> members=new ArrayList<Customer>();
    @Override
    public void register(Customer member) {
        if(!members.contains(member)){
            members.add(member);
            member.setMedium(this);
        }
    }

    @Override
    public void relay(String from, String ad) {
        for (Customer member : members) {
            String name=member.getName();
            if(!name.equals(from)){
                ((Customer)member).receive(from,ad);
            }
        }
    }
}

//抽象同事类:客户
abstract class Customer extends JFrame implements ActionListener{
    protected Medium medium;
    protected String name;
    JTextField SentText;
    JTextArea ReceiveArea;

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

    void ClientWindow(int x,int y){
        Container cp;
        JScrollPane sp;
        JPanel p1,p2;
        cp=this.getContentPane();
        SentText=new JTextField(30);
        ReceiveArea=new JTextArea(18,30);
        ReceiveArea.setEditable(false);
        p1=new JPanel();
        p1.setBorder(BorderFactory.createTitledBorder("接收内容:"));
        p1.add(ReceiveArea);
        sp=new JScrollPane(p1);
        cp.add(sp,BorderLayout.NORTH);
        p2=new JPanel();
        p2.setBorder(BorderFactory.createTitledBorder("发送内容:"));
        p2.add(SentText);
        cp.add(p2,BorderLayout.SOUTH);
        SentText.addActionListener(this);
        this.setLocation(x,y);
        this.setSize(550, 430);
        this.setResizable(false); //窗口大小不可调整
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String tempInfo=SentText.getText().trim();
        SentText.setText("");
        this.send(tempInfo);
    }
    public String getName(){
        return name;
    }
    public void setMedium(Medium medium){
        this.medium=medium;
    }
    public abstract void send(String ad);
    public abstract void receive(String from,String ad);
}

//具体同事类:卖方
class Seller extends Customer
{
    public Seller(String name)
    {
        super(name);
        ClientWindow(50,100);
    }
    public void send(String ad)
    {
        ReceiveArea.append("我(卖方)说: "+ad+"\n");
        //使滚动条滚动到最底端
        ReceiveArea.setCaretPosition(ReceiveArea.getText().length());
        medium.relay(name,ad);
    }
    public void receive(String from,String ad)
    {
        ReceiveArea.append(from +"说: "+ad+"\n");
        //使滚动条滚动到最底端
        ReceiveArea.setCaretPosition(ReceiveArea.getText().length());
    }
}
//具体同事类:买方
class Buyer extends Customer
{
    public Buyer(String name)
    {
        super(name);
        ClientWindow(350,100);
    }
    public void send(String ad)
    {
        ReceiveArea.append("我(买方)说: "+ad+"\n");
        //使滚动条滚动到最底端
        ReceiveArea.setCaretPosition(ReceiveArea.getText().length());
        medium.relay(name,ad);
    }
    public void receive(String from,String ad)
    {
        ReceiveArea.append(from +"说: "+ad+"\n");
        //使滚动条滚动到最底端
        ReceiveArea.setCaretPosition(ReceiveArea.getText().length());
    }
}

public class DatingPlatform
{
    public static void main(String[] args)
    {
        Medium md=new EstateMedium();    //房产中介
        Customer member1,member2;
        member1=new Seller("Seller(卖方)");
        member2=new Buyer("Buyer(买方)");
        md.register(member1); //客户注册
        md.register(member2);
    }
}

程序输出结果如下:

简而言之:中介者模式是通过中介者对象,使用List挂载需要管理的连接对象,连接对象在发生变化时,不通过对象之间直接进行通信,而是让中介者进行信息转发(relay),中介者在List中遍历,将发送者外的其他对象进行信息通知,实现类之间的解耦。

主要参考:http://c.biancheng.net/view

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页