【例】通过按钮来控制一个电梯的状态,一个电梯有开门状态,关门状态,停止状态,运行状态。每一种状态改变,都有可能要根据其他状态来更新处理。例如,如果电梯门现在处于运行时状态,就不能进行开门操作,而如果电梯门是停止状态,就可以执行开门操作。
类图如下:

- public interface ILift {
- //电梯的4个状态
- //开门状态
- public final static int OPENING_STATE = 1;
- //关门状态
- public final static int CLOSING_STATE = 2;
- //运行状态
- public final static int RUNNING_STATE = 3;
- //停止状态
- public final static int STOPPING_STATE = 4;
-
- //设置电梯的状态
- public void setState(int state);
-
- //电梯的动作
- public void open();
- public void close();
- public void run();
- public void stop();
- }
-
- public class Lift implements ILift {
- private int state;
-
- @Override
- public void setState(int state) {
- this.state = state;
- }
-
- //执行关门动作
- @Override
- public void close() {
- switch (this.state) {
- case OPENING_STATE:
- System.out.println("电梯关门了。。。");//只有开门状态可以关闭电梯门,可以对应电梯状态表来看
- this.setState(CLOSING_STATE);//关门之后电梯就是关闭状态了
- break;
- case CLOSING_STATE:
- //do nothing //已经是关门状态,不能关门
- break;
- case RUNNING_STATE:
- //do nothing //运行时电梯门是关着的,不能关门
- break;
- case STOPPING_STATE:
- //do nothing //停止时电梯也是关着的,不能关门
- break;
- }
- }
-
- //执行开门动作
- @Override
- public void open() {
- switch (this.state) {
- case OPENING_STATE://门已经开了,不能再开门了
- //do nothing
- break;
- case CLOSING_STATE://关门状态,门打开:
- System.out.println("电梯门打开了。。。");
- this.setState(OPENING_STATE);
- break;
- case RUNNING_STATE:
- //do nothing 运行时电梯不能开门
- break;
- case STOPPING_STATE:
- System.out.println("电梯门开了。。。");//电梯停了,可以开门了
- this.setState(OPENING_STATE);
- break;
- }
- }
-
- //执行运行动作
- @Override
- public void run() {
- switch (this.state) {
- case OPENING_STATE://电梯不能开着门就走
- //do nothing
- break;
- case CLOSING_STATE://门关了,可以运行了
- System.out.println("电梯开始运行了。。。");
- this.setState(RUNNING_STATE);//现在是运行状态
- break;
- case RUNNING_STATE:
- //do nothing 已经是运行状态了
- break;
- case STOPPING_STATE:
- System.out.println("电梯开始运行了。。。");
- this.setState(RUNNING_STATE);
- break;
- }
- }
-
- //执行停止动作
- @Override
- public void stop() {
- switch (this.state) {
- case OPENING_STATE: //开门的电梯已经是是停止的了(正常情况下)
- //do nothing
- break;
- case CLOSING_STATE://关门时才可以停止
- System.out.println("电梯停止了。。。");
- this.setState(STOPPING_STATE);
- break;
- case RUNNING_STATE://运行时当然可以停止了
- System.out.println("电梯停止了。。。");
- this.setState(STOPPING_STATE);
- break;
- case STOPPING_STATE:
- //do nothing
- break;
- }
- }
- }
-
- public class Client {
- public static void main(String[] args) {
- Lift lift = new Lift();
- lift.setState(ILift.STOPPING_STATE);//电梯是停止的
- lift.open();//开门
- lift.close();//关门
- lift.run();//运行
- lift.stop();//停止
- }
- }
问题分析:
定义:
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
状态模式包含以下主要角色。
对上述电梯的案例使用状态模式进行改进。类图如下:

- //抽象状态类
- public abstract class LiftState {
- //定义一个环境角色,也就是封装状态的变化引起的功能变化
- protected Context context;
-
- public void setContext(Context context) {
- this.context = context;
- }
-
- //电梯开门动作
- public abstract void open();
-
- //电梯关门动作
- public abstract void close();
-
- //电梯运行动作
- public abstract void run();
-
- //电梯停止动作
- public abstract void stop();
- }
-
- //开启状态
- public class OpenningState extends LiftState {
-
- //开启当然可以关闭了,我就想测试一下电梯门开关功能
- @Override
- public void open() {
- System.out.println("电梯门开启...");
- }
-
- @Override
- public void close() {
- //状态修改
- super.context.setLiftState(Context.closeingState);
- //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
- super.context.getLiftState().close();
- }
-
- //电梯门不能开着就跑,这里什么也不做
- @Override
- public void run() {
- //do nothing
- }
-
- //开门状态已经是停止的了
- @Override
- public void stop() {
- //do nothing
- }
- }
-
- //运行状态
- public class RunningState extends LiftState {
-
- //运行的时候开电梯门?你疯了!电梯不会给你开的
- @Override
- public void open() {
- //do nothing
- }
-
- //电梯门关闭?这是肯定了
- @Override
- public void close() {//虽然可以关门,但这个动作不归我执行
- //do nothing
- }
-
- //这是在运行状态下要实现的方法
- @Override
- public void run() {
- System.out.println("电梯正在运行...");
- }
-
- //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
- @Override
- public void stop() {
- super.context.setLiftState(Context.stoppingState);
- super.context.stop();
- }
- }
-
- //停止状态
- public class StoppingState extends LiftState {
-
- //停止状态,开门,那是要的!
- @Override
- public void open() {
- //状态修改
- super.context.setLiftState(Context.openningState);
- //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
- super.context.getLiftState().open();
- }
-
- @Override
- public void close() {//虽然可以关门,但这个动作不归我执行
- //状态修改
- super.context.setLiftState(Context.closeingState);
- //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
- super.context.getLiftState().close();
- }
-
- //停止状态再跑起来,正常的很
- @Override
- public void run() {
- //状态修改
- super.context.setLiftState(Context.runningState);
- //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
- super.context.getLiftState().run();
- }
-
- //停止状态是怎么发生的呢?当然是停止方法执行了
- @Override
- public void stop() {
- System.out.println("电梯停止了...");
- }
- }
-
- //关闭状态
- public class ClosingState extends LiftState {
-
- @Override
- //电梯门关闭,这是关闭状态要实现的动作
- public void close() {
- System.out.println("电梯门关闭...");
- }
-
- //电梯门关了再打开,逗你玩呢,那这个允许呀
- @Override
- public void open() {
- super.context.setLiftState(Context.openningState);
- super.context.open();
- }
-
-
- //电梯门关了就跑,这是再正常不过了
- @Override
- public void run() {
- super.context.setLiftState(Context.runningState);
- super.context.run();
- }
-
- //电梯门关着,我就不按楼层
- @Override
- public void stop() {
- super.context.setLiftState(Context.stoppingState);
- super.context.stop();
- }
- }
-
- //环境角色
- public class Context {
- //定义出所有的电梯状态
- public final static OpenningState openningState = new OpenningState();//开门状态,这时候电梯只能关闭
- public final static ClosingState closeingState = new ClosingState();//关闭状态,这时候电梯可以运行、停止和开门
- public final static RunningState runningState = new RunningState();//运行状态,这时候电梯只能停止
- public final static StoppingState stoppingState = new StoppingState();//停止状态,这时候电梯可以开门、运行
-
-
- //定义一个当前电梯状态
- private LiftState liftState;
-
- public LiftState getLiftState() {
- return this.liftState;
- }
-
- public void setLiftState(LiftState liftState) {
- //当前环境改变
- this.liftState = liftState;
- //把当前的环境通知到各个实现类中
- this.liftState.setContext(this);
- }
-
- public void open() {
- this.liftState.open();
- }
-
- public void close() {
- this.liftState.close();
- }
-
- public void run() {
- this.liftState.run();
- }
-
- public void stop() {
- this.liftState.stop();
- }
- }
-
- //测试类
- public class Client {
- public static void main(String[] args) {
- Context context = new Context();
- context.setLiftState(new ClosingState());
-
- context.open();
- context.close();
- context.run();
- context.stop();
- }
- }
1,优点:
2,缺点:
定义:
又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
在观察者模式中有如下角色:
【例】微信公众号
在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号。
类图如下:

定义抽象观察者类,里面定义一个更新的方法
public interface Observer {
void update(String message);
}
定义具体观察者类,微信用户是观察者,里面实现了更新的方法
public class WeixinUser implements Observer {
// 微信用户名
private String name;
public WeixinUser(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "-" + message);
}
}
定义抽象主题类,提供了attach、detach、notify三个方法
public interface Subject {
//增加订阅者
public void attach(Observer observer);
//删除订阅者
public void detach(Observer observer);
//通知订阅者更新消息
public void notify(String message);
}
微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法
public class SubscriptionSubject implements Subject {
//储存订阅公众号的微信用户
private List weixinUserlist = new ArrayList();
@Override
public void attach(Observer observer) {
weixinUserlist.add(observer);
}
@Override
public void detach(Observer observer) {
weixinUserlist.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer : weixinUserlist) {
observer.update(message);
}
}
}
客户端程序
public class Client { public static void main(String[] args) { SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject(); //创建微信用户 WeixinUser user1=new WeixinUser("孙悟空"); WeixinUser user2=new WeixinUser("猪悟能"); WeixinUser user3=new WeixinUser("沙悟净"); //订阅公众号 mSubscriptionSubject.attach(user1); mSubscriptionSubject.attach(user2); mSubscriptionSubject.attach(user3); //公众号更新发出消息给订阅的微信用户 mSubscriptionSubject.notify("传智黑马的专栏更新了"); } }6.6.4 优缺点
1,优点:
2,缺点:
在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。
1,Observable类
Observable 类是抽象目标类(被观察者),它有一个 Vector 集合成员变量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。
2,Observer 接口
Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 update 方法,进行相应的工作。
【例】警察抓小偷
警察抓小偷也可以使用观察者模式来实现,警察是观察者,小偷是被观察者。代码如下:
小偷是一个被观察者,所以需要继承Observable类
public class Thief extends Observable {
private String name;
public Thief(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void steal() {
System.out.println("小偷:我偷东西了,有没有人来抓我!!!");
super.setChanged(); //changed = true
super.notifyObservers();
}
}
警察是一个观察者,所以需要让其实现Observer接口
public class Policemen implements Observer {
-
- private String name;
-
- public Policemen(String name) {
- this.name = name;
- }
- public void setName(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public void update(Observable o, Object arg) {
- System.out.println("警察:" + ((Thief) o).getName() + ",我已经盯你很久了,你可以保持沉默,但你所说的将成为呈堂证供!!!");
- }
- }
- public class Policemen implements Observer {
-
- private String name;
-
- public Policemen(String name) {
- this.name = name;
- }
- public void setName(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public void update(Observable o, Object arg) {
- System.out.println("警察:" + ((Thief) o).getName() + ",我已经盯你很久了,你可以保持沉默,但你所说的将成为呈堂证供!!!");
- }
- }
一般来说,同事类之间的关系是比较复杂的,多个同事类之间互相关联时,他们之间的关系会呈现为复杂的网状结构,这是一种过度耦合的架构,即不利于类的复用,也不稳定。例如在下左图中,有六个同事类对象,假如对象1发生变化,那么将会有4个对象受到影响。如果对象2发生变化,那么将会有5个对象受到影响。也就是说,同事类之间直接关联的设计是不好的。
如果引入中介者模式,那么同事类之间的关系将变为星型结构,从下右图中可以看到,任何一个类的变动,只会影响的类本身,以及中介者,这样就减小了系统的耦合。一个好的设计,必定不会把所有的对象关系处理逻辑封装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。
定义:
又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。
中介者模式包含以下主要角色:
【例】租房
现在租房基本都是通过房屋中介,房主将房屋托管给房屋中介,而租房者从房屋中介获取房屋信息。房屋中介充当租房者与房屋所有者之间的中介者。
类图如下:

- //抽象中介者
- public abstract class Mediator {
- //申明一个联络方法
- public abstract void constact(String message,Person person);
- }
-
- //抽象同事类
- public abstract class Person {
- protected String name;
- protected Mediator mediator;
-
- public Person(String name,Mediator mediator){
- this.name = name;
- this.mediator = mediator;
- }
- }
-
- //具体同事类 房屋拥有者
- public class HouseOwner extends Person {
-
- public HouseOwner(String name, Mediator mediator) {
- super(name, mediator);
- }
-
- //与中介者联系
- public void constact(String message){
- mediator.constact(message, this);
- }
-
- //获取信息
- public void getMessage(String message){
- System.out.println("房主" + name +"获取到的信息:" + message);
- }
- }
-
- //具体同事类 承租人
- public class Tenant extends Person {
- public Tenant(String name, Mediator mediator) {
- super(name, mediator);
- }
-
- //与中介者联系
- public void constact(String message){
- mediator.constact(message, this);
- }
-
- //获取信息
- public void getMessage(String message){
- System.out.println("租房者" + name +"获取到的信息:" + message);
- }
- }
-
- //中介机构
- public class MediatorStructure extends Mediator {
- //首先中介结构必须知道所有房主和租房者的信息
- private HouseOwner houseOwner;
- private Tenant tenant;
-
- public HouseOwner getHouseOwner() {
- return houseOwner;
- }
-
- public void setHouseOwner(HouseOwner houseOwner) {
- this.houseOwner = houseOwner;
- }
-
- public Tenant getTenant() {
- return tenant;
- }
-
- public void setTenant(Tenant tenant) {
- this.tenant = tenant;
- }
-
- public void constact(String message, Person person) {
- if (person == houseOwner) { //如果是房主,则租房者获得信息
- tenant.getMessage(message);
- } else { //反正则是房主获得信息
- houseOwner.getMessage(message);
- }
- }
- }
-
- //测试类
- public class Client {
- public static void main(String[] args) {
- //一个房主、一个租房者、一个中介机构
- MediatorStructure mediator = new MediatorStructure();
-
- //房主和租房者只需要知道中介机构即可
- HouseOwner houseOwner = new HouseOwner("张三", mediator);
- Tenant tenant = new Tenant("李四", mediator);
-
- //中介结构要知道房主和租房者
- mediator.setHouseOwner(houseOwner);
- mediator.setTenant(tenant);
-
- tenant.constact("需要租三室的房子");
- houseOwner.constact("我这有三室的房子,你需要租吗?");
- }
- }
1,优点:
2,缺点:
当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。
定义:
提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
迭代器模式主要包含以下角色:
【例】定义一个可以存储学生对象的容器对象,将遍历该容器的功能交由迭代器实现,涉及到的类如下:

定义迭代器接口,声明hasNext、next方法
public interface StudentIterator {
boolean hasNext();
Student next();
}
定义具体的迭代器类,重写所有的抽象方法
public class StudentIteratorImpl implements StudentIterator {
private List list;
private int position = 0;
public StudentIteratorImpl(List list) {
this.list = list;
}
@Override
public boolean hasNext() {
return position < list.size();
}
@Override
public Student next() {
Student currentStudent = list.get(position);
position ++;
return currentStudent;
}
}
定义抽象容器类,包含添加元素,删除元素,获取迭代器对象的方法
public interface StudentAggregate {
void addStudent(Student student);
void removeStudent(Student student);
StudentIterator getStudentIterator();
}
定义具体的容器类,重写所有的方法
public class StudentAggregateImpl implements StudentAggregate {
private List list = new ArrayList(); // 学生列表
@Override
public void addStudent(Student student) {
this.list.add(student);
}
@Override
public void removeStudent(Student student) {
this.list.remove(student);
}
@Override
public StudentIterator getStudentIterator() {
return new StudentIteratorImpl(list);
}
}
1,优点:
2,缺点:
增加了类的个数,这在一定程度上增加了系统的复杂性。
迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的。
Listlist = new ArrayList<>(); Iterator iterator = list.iterator(); //list.iterator()方法返回的肯定是Iterator接口的子实现类对象 while (iterator.hasNext()) { System.out.println(iterator.next()); }
看完这段代码是不是很熟悉,与我们上面代码基本类似。单列集合都使用到了迭代器,我们以ArrayList举例来说明
具体的来看看 ArrayList的代码实现
- public class ArrayList
extends AbstractList - implements List
, RandomAccess, Cloneable, java.io.Serializable { -
- public Iterator
iterator() { - return new Itr();
- }
-
- private class Itr implements Iterator
{ - int cursor; // 下一个要返回元素的索引
- int lastRet = -1; // 上一个返回元素的索引
- int expectedModCount = modCount;
-
- Itr() {}
-
- //判断是否还有元素
- public boolean hasNext() {
- return cursor != size;
- }
-
- //获取下一个元素
- public E next() {
- checkForComodification();
- int i = cursor;
- if (i >= size)
- throw new NoSuchElementException();
- Object[] elementData = ArrayList.this.elementData;
- if (i >= elementData.length)
- throw new ConcurrentModificationException();
- cursor = i + 1;
- return (E) elementData[lastRet = i];
- }
- ...
- }
这部分代码还是比较简单,大致就是在 iterator 方法中返回了一个实例化的 Iterator 对象。Itr是一个内部类,它实现了 Iterator 接口并重写了其中的抽象方法。
注意:
当我们在使用JAVA开发的时候,想使用迭代器模式的话,只要让我们自己定义的容器类实现java.util.Iterable并实现其中的iterator()方法使其返回一个 java.util.Iterator 的实现类就可以了。