本文主要介绍Java面向对象23种设计模式中行为型模式中的部分设计模式,上接Java面向对象设计模式学习(五)。
四、责任链模式
责任链模式,也称职责链模式,主要面向以下问题:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。
责任链模式是指:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
该模式下客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,实现了请求发送与处理的解耦。
责任链模式主要角色如下:
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(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语句对所有情况进行判断处理,违背了“开闭原则”,难以进行扩展。
状态模式的解决思想是:当控制一个对象状态转换的条件表达式过于复杂时,把相关“判断逻辑”提取出来,放到一系列的状态类当中,这样可以把原来复杂的逻辑判断简单化。
状态模式的主要角色如下:
- 环境(Context)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
- 具体状态(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.
六、观察者模式
观察者模式,又称发布-订阅模式,是指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式的主要角色如下:
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(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 服务器等。
中介者模式的关键是找出中介者 ,模式主要角色如下:
- 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
- 具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
- 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
- 具体同事类(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中遍历,将发送者外的其他对象进行信息通知,实现类之间的解耦。