行为型模式总结
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
一. 模版方法模式
模版方法模式定义一个算法的骨架,将算法的一些步骤延迟到子类中,使得子类在可以不改变算法结构的情况下重新定义该算法的某些特定步骤。
模版方法模式的核心组件:
(1) 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。
① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
② 基本方法:是整个算法中的一个步骤,包含以下几种类型。
抽象方法:在抽象类中申明,由具体子类实现。
具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
1. 类图

2. 代码实现
package cn.design.templatemethod14;
/*抽象类*/
public abstract class AbstractClass {
public abstract void abstractMethod1();//抽象方法1,也称作钩子函数。
public abstract void abstractMethod2();//抽象方法2
private void SpecificMethod() {//具体方法
System.out.println("抽象类中的具体方法被调用!");
}
public final void TemplateMethod() {//模板方法,把基本操作组合到一起,子类一般不能重写
abstractMethod1();
SpecificMethod();
abstractMethod2();
}
}
package cn.design.templatemethod14;
public class Client {
public static void main(String[] args) {
AbstractClass method = new ConcreteClass();
method.TemplateMethod();
/*
* 在定义子类的时候,可以采用匿名内部类的方式
*/
/*AbstractClass method2 = new AbstractClass() {
@Override
public void abstractMethod1() {
System.out.println("抽象方法1的实现被调用!");
}
@Override
public void abstractMethod2() {
System.out.println("抽象方法2的实现被调用!");
}
};
method2.TemplateMethod();
*/
}
}
/*具体子类,按照客户需求,进行重写抽象方法*/
class ConcreteClass extends AbstractClass{
@Override
public void abstractMethod1() {
System.out.println("抽象方法1的实现被调用!");
}
@Override
public void abstractMethod2() {
System.out.println("抽象方法2的实现被调用!");
}
}
二. 命令模式
命令(Command)模式的定义如下:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。
命令模式的核心组件:
抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
具体命令角色(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。
1. 类图

2. 代码实现
package cn.design.command15;
/*抽象命令*/
public interface Command {
public abstract void execute();
}
/*具体命令*/
class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand() {
this.receiver = new Receiver();
}
@Override
public void execute() {
receiver.action();
}
}
/*接收者*/
class Receiver {
public void action() {
System.out.println("接收者的action方法被调用!");
}
}
/*调用者*/
class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void setCommand(Command command) {
this.command = command;
}
public void call(){
System.out.println("调用者执行命令command……");
command.execute();
}
}
package cn.design.command15;
public class Client {
public static void main(String[] args) {
Command command = new ConcreteCommand();
Invoker invoker = new Invoker(command);
invoker.call();
}
}
三. 迭代器模式
迭代器(Iterator)模式的定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。(将聚合对象中的集合传入具体迭代器里进行访问)。
迭代器模式主要包含以下角色:
抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
1. 类图

2. 代码实现
package cn.design.summary.Iterator;
import java.util.ArrayList;
import java.util.List;
/*抽象聚合角色*/
public interface IAggregate {
public void add(Object obj);
public void remove(Object obj);
public IIterator getIterator();
}
/*具体聚合角色*/
class ConcreteAggregate implements IAggregate {
private List<Object> list = new ArrayList<Object> ();
@Override
public void add(Object obj) {
list.add(obj);
}
@Override
public void remove(Object obj) {
list.remove(obj);
}
@Override
public IIterator getIterator() {
return new ConcreteIterator(list);
}
}
package cn.design.summary.Iterator;
import java.util.List;
/*抽象迭代器*/
public interface IIterator {
Object getFirst();
Object next();
Boolean hasNext();
}
/*具体迭代器*/
class ConcreteIterator implements IIterator {
private List<Object> list = null;
private int index = -1; //定义游标用于记录遍历的位置
//通过迭代器的构造方法将聚合类中的集合传进来
public ConcreteIterator(List<Object> list) {
this.list = list;
}
@Override
public Object getFirst() {
index = 0;
return list.get(index);
}
@Override
public Object next() {
Object obj = null;
if(this.hasNext()){
obj = list.get(++index);//每次获取元素以后,index+1,保证区到的元素是下一个
}
return obj;
}
@Override
public Boolean hasNext() {
return index < list.size() - 1 ? true : false;
}
}
package cn.design.summary.Iterator;
public class Client {
public static void main(String[] args) {
ConcreteAggregate conAgg = new ConcreteAggregate();
conAgg.add("aa");
conAgg.add("bb");
conAgg.add("cc");
IIterator iter = conAgg.getIterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
}
迭代器模式的重点在于具体聚合类里的集合传给具体迭代器对象,通过具体迭代器对象对该集合进行访问操作。
四. 观察者模式
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
观察者模式的核心组件:
抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的集合和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体目标的更改通知时被调用。
具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
1. 类图

2. 代码实现
package cn.design.observer17;
import java.util.ArrayList;
import java.util.List;
/*抽象目标对象*/
public abstract class Subject {
//存放观察者对象的集合
protected List<IObserver> list = new ArrayList<>();
//添加观察者
public void registerObs(IObserver obs) {
list.add(obs);
}
//删除观察者
public void removeObs(IObserver obs) {
list.remove(obs);
}
/*
*通知观察者的方法
*/
public abstract void notifyAllObservers();
}
package cn.design.observer17;
/*具体目标对象*/
public class ConcreteSubject extends Subject {
private int state; //定义一个状态属性
/*
*实现父类的抽象通知方法
*/
@Override
public void notifyAllObservers() {
for(IObserver obs : super.list){
obs.update(this);
}
}
public int getState() {
return state;
}
/*
*在更改state时执行通知方法
*/
public void setState(int state) {
this.state = state;
//目标对象值发生了变化,通知所有的观察者
this.notifyAllObservers();
}
}
package cn.design.observer17;
/*观察者接口*/
public interface IObserver {
//抽象的更新方法
void update(Subject subject);
}
package cn.design.observer17;
/*具体观察者*/
public class ObserverImpl implements IObserver {
private int myState; //myState需要跟目标对象的值保持一致
public int getMyState() {
return myState;
}
public void setMyState(int myState) {
this.myState = myState;
}
/*
* 实现父类的的更新方法
*/
@Override
public void update(Subject subject) {
myState = ((ConcreteSubject)subject).getState();
}
}
package cn.design.observer17;
public class Client {
public static void main(String[] args) {
//创建目标对象
ConcreteSubject subject = new ConcreteSubject();
//创建多个观察者
ObserverImpl obs1 = new ObserverImpl();
ObserverImpl obs2 = new ObserverImpl();
ObserverImpl obs3 = new ObserverImpl();
//将多个观察者添加到subject对象的观察者队伍中
subject.registerObs(obs1);
subject.registerObs(obs2);
subject.registerObs(obs3);
//改变subject的状态
subject.setState(3000);
//看看观察者的变化
System.out.println("观察者的变化:");
System.out.println(obs1.getMyState());
System.out.println(obs2.getMyState());
System.out.println(obs3.getMyState());
}
}
观察者模式的重点是将观察者对象存储到目标对象的集合中去,通过调用目标对象的通知方法,遍历集合,依次执行观察者对象的更新方法更新观察者对象的状态。
五. 中介者模式
中介者(Mediator)模式的定义:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。
中介者模式的核心组件:
抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
1. 类图

2. 代码实现
package cn.design.mediator20;
import java.util.ArrayList;
import java.util.List;
/*抽象中介者*/
public interface Mediator {
void register(Colleague colleague); //同事类在中介者的集合中注册
void relay(Colleague cl); //转发
}
/*具体中介者*/
class ConcreteMediator implements Mediator {
/*
*定义一个集合存储同事类
*/
private List<Colleague> list = new ArrayList<>();
/*
*具体注册方法
*/
@Override
public void register(Colleague colleague) {
if(!list.contains(colleague)){
list.add(colleague);
colleague.setMediator(this); //将中介者本身设置给同事类持有
}
}
/*
*具体转发方法
*/
@Override
public void relay(Colleague cl) { //cl为发出请求的具体同事类
/*
*cl通过中介者调用所有的其他同事类
*/
for (Colleague colleague : list) {
if(!colleague.equals(cl)){
colleague.receive();
}
}
}
}
package cn.design.mediator20;
/*抽象同事类*/
abstract class Colleague {
protected Mediator mediator; //持有中介者对象
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive(); //接收请求,完成本部门的事情
public abstract void send(); //发送请求
}
/*
*具体同事类1
*/
class ConcreteColleague1 extends Colleague {
@Override
public void receive() {
System.out.println("具体同事类1接收到请求,完成本部门的事情!");
}
@Override
public void send() {
System.out.println("具体同事类1发出请求!");
mediator.relay(this); //请中介者转发请求
}
}
/*
*具体同事类2
*/
class ConcreteColleague2 extends Colleague {
@Override
public void receive() {
System.out.println("具体同事类2接收到请求,完成本部门的事情!");
}
@Override
public void send() {
System.out.println("具体同事类2发出请求!");
mediator.relay(this); //请中介者转发请求
}
}
package cn.design.mediator20;
public class Client {
public static void main(String[] args) {
Mediator mediator = new ConcreteMediator();
Colleague colleague1 = new ConcreteColleague1();
Colleague colleague2 = new ConcreteColleague2();
mediator.register(colleague1);
mediator.register(colleague2);
colleague1.send();
}
}
中介者模式的核心思想是将具体同事类在具体中介者类中的集合进行注册,并且每个同事类本身都持有一个中介者类的对象,这样的话可以保证每一个同事类可以通过中介者对象的转发方法去请求集合中的其他同事类,使得同事类之间的直接联系被切断,实现了解耦合。
六. 责任链模式
责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。(将能够处理同一请求的对象连接成一条链)。
责任链模式的核心组件:
抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
1. 类图

2. 代码实现
package cn.design.chainofresp19;
/*责任链的抽象处理者*/
public abstract class AbstractLeader {
protected String name;
protected AbstractLeader nextLeader; //责任链上的后继对象
public AbstractLeader(String name) {
this.name = name;
}
//设置责任链上的后继对象
public void setNextLeader(AbstractLeader nextLeader) {
this.nextLeader = nextLeader;
}
//处理请求的核心业务方法
public abstract void handleRequest(LeaveRequest request);
}
package cn.design.chainofresp19;
/*主任*/
public class Director extends AbstractLeader{
public Director(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if(request.getLeaveDays() < 3){
System.out.println("员工"+request.getEmpName()+"请假"+request.getLeaveDays()+"天"+"理由:"+request.getResson());
System.out.println("主任:"+this.name+"审批通过!");
}else {
this.nextLeader.handleRequest(request);
}
}
}
package cn.design.chainofresp19;
/*经理*/
public class Manger extends AbstractLeader{
public Manger(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if(request.getLeaveDays() < 30){
System.out.println("员工"+request.getEmpName()+"请假"+request.getLeaveDays()+"天"+"理由:"+request.getResson());
System.out.println("经理:"+this.name+"审批通过!");
}else {
System.out.println("超过30天不审批");
}
}
}
package cn.design.chainofresp19;
public class Client {
public static void main(String[] args) {
AbstractLeader a = new Director("张三");
AbstractLeader b = new Manger("李四");
//组织责任链对象关系
a.setNextLeader(b);
LeaveRequest request = new LeaveRequest("TOM",10,"回英国老家探亲");
a.handleRequest(request);
}
}
package cn.design.chainofresp19;
/*请假请求类*/
public class LeaveRequest {
private String empName;
private int leaveDays;
private String resson;
public LeaveRequest(String empName, int leaveDays, String resson) {
this.empName = empName;
this.leaveDays = leaveDays;
this.resson = resson;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public int getLeaveDays() {
return leaveDays;
}
public void setLeaveDays(int leaveDays) {
this.leaveDays = leaveDays;
}
public String getResson() {
return resson;
}
public void setResson(String resson) {
this.resson = resson;
}
}
责任链模式的核心是将能够处理同一请求的对象链接成一条责任链,其中每个具体处理者对象持有下一个处理者对象,如果其本身处理不了该请求,可以将请求转发到下一个对象处理。
七. 策略模式
策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。(将算法的实现和使用分离)
策略模式的核心组件:
抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
环境(Context)类:持有一个策略类的引用,最终给客户端调用。
1. 类图

2. 代码实现
package cn.design.strategy18;
/*
* 上下文类,对算法进行管理
* 负责和具体的策略类交互,这样的话,具体的算法和直接的客户端调用隔离了,使得算法可以独立于客户端变化。
*/
public class Context {
private IStrategy strategy;
//构造方法注入具体的策略
public Context(IStrategy strategy) {
this.strategy = strategy;
}
public void printPrice(double s) {
System.out.println("您该报价:" + strategy.getPrice(s));
}
}
package cn.design.strategy18;
/*抽象的策略接口*/
public interface IStrategy {
public double getPrice(double standarPrice);
}
package cn.design.strategy18;
/*策略模式的具体实现类*/
public class NewCustomerFewStrategy implements IStrategy {
@Override
public double getPrice(double standarPrice) {
System.out.println("普通客户小批量不打折!");
return standarPrice;
}
}
package cn.design.strategy18;
/*策略模式的具体实现类*/
public class NewCustomerManyStrategy implements IStrategy {
@Override
public double getPrice(double standarPrice) {
System.out.println("普通客户大批量打九折!");
return standarPrice*0.9;
}
}
package cn.design.strategy18;
/*策略模式的具体实现类*/
public class OldCustomerFewStrategy implements IStrategy {
@Override
public double getPrice(double standarPrice) {
System.out.println("老客户小批量打八五折!");
return standarPrice*0.85;
}
}
package cn.design.strategy18;
/*策略模式的具体实现类*/
public class OldCustomerManyStrategy implements IStrategy {
@Override
public double getPrice(double standarPrice) {
System.out.println("老客户大批量打八折!");
return standarPrice*0.8;
}
}
package cn.design.strategy18;
public class Client {
public static void main(String[] args) {
IStrategy strategy = new NewCustomerManyStrategy();
Context context = new Context(strategy);
context.printPrice(100);
}
}
策略模式的核心思想是上下文类持有一个抽象策略的引用,将具体的策略注入上下文类的对象,用户通过调用上下文类注入需要的策略。注:在策略模式中,对于用户来说,用户很明确的知道每个策略算法,可以按照自己的需求选择调用哪个算法,这也是和状态模式的区别,在状态模式中,用户是不知道状态内部的具体实现的。
八. 状态模式
状态(State)模式的定义:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
状态模式的核心组件:
环境(Context)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
具体状态(Concrete State)角色:实现抽象状态所对应的行为。
1. 类图

2. 代码实现
package cn.design.state21;
/*抽象状态接口*/
public interface IState {
void handle(Context context);
}
class ConcreteStateA implements IState {
@Override
public void handle(Context context) {
System.out.println("当前状态是A");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB implements IState {
@Override
public void handle(Context context) {
System.out.println("当前状态是B");
context.setState(new ConcreteStateC());
}
}
class ConcreteStateC implements IState {
@Override
public void handle(Context context) {
System.out.println("当前状态是C");
context.setState(new ConcreteStateA());
}
}
package cn.design.state21;
/*上下文类*/
public class Context {
private IState state; //上下文类持有当前状态
/*
* 初始化状态为第一个具体状态类
*/
public Context() {
this.state = new ConcreteStateA();
}
/*
* set方法设置状态
*/
public void setState(IState state) {
this.state = state;
}
/*
* 执行state对象的内部方法
*/
public void handle(){
state.handle(this);
}
}
package cn.design.state21;
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.handle();
context.handle();
context.handle();
context.handle();
}
}
状态模式和策略模式在类图上其实看不出多大区别,但是要注意的一点是,状态模式对于用户来说,并不知道状态内部方法是如何实现的,Context对象状态的切换也在各个状态内部方法中自动完成,但是在策略模式中,用户是清楚各个策略算法的实现的,可以根据需要选择策略算法注入Context对象。
九. 备忘录模式
备忘录(Memento)模式的定义:在不破坏源生器类封装性的前提下,捕获其内部状态,并在该对象之外(即备忘录类)保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。
备忘录模式的核心组件:
源发器(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
备忘录(Memento)角色:负责存储源发器的内部状态,在需要的时候提供这些内部状态给源发器。
管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改(可以提供一个容器,存储多个备忘录)。
1. 类图

2. 代码实现
package cn.design.memento22;
/*源发器类*/
public class Originator {
private String name;
private int age;
private double salary;
/*
* 进行备忘操作,并返回备忘录对象
*/
public Memento memento(){
return new Memento(this);
}
/*
* 进行数据恢复,恢复成制定备忘录对象的值
*/
public void recovery(Memento memento){
this.name = memento.getName();
this.age = memento.getAge();
this.salary = memento.getSalary();
}
public Originator(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package cn.design.memento22;
/*备忘录类*/
public class Memento {
private String name;
private int age;
private double salary;
/*
* 通过构造方法,将源发器类对象的内部状态信息复制给备忘录类
*/
public Memento(Originator originator){
this.name = originator.getName();
this.age = originator.getAge();
this.salary = originator.getSalary();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package cn.design.memento22;
/*负责人类,负责管理备忘录对象*/
public class CareTaker {
private Memento memento;
/*
* 如果备忘多次可以创建一个容器存储备忘录
* private List<Memento> list = new ArrayList<>();
*/
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
package cn.design.memento22;
public class Client {
public static void main(String[] args) {
CareTaker taker = new CareTaker();
//创建源生器类对象
Originator originator = new Originator("chaochao", 18, 1000);
taker.setMemento(originator.memento()); //做了一次备份
//修改源生类对象
originator.setName("chaochao2");
originator.setAge(19);
originator.setSalary(2000);
//通过备忘录恢复
originator.recovery(taker.getMemento());
System.out.println(originator.getName()+" 年龄: "+originator.getAge()+" salary: "+originator.getSalary());
}
}
备忘录模式的核心思想是将源发器对象的内部信息在备忘录对象中存储一份,然后将备忘录对象存储在负责人类里统一管理。用户可以通过源发器类的备份方法进行备份,恢复方法进行恢复。