行为型模式
1. 状态模式
1.1 概述
例通过按钮控制电梯的状态。电梯具有开门、关门、停止和运行状态。每种状态变化都可以根据其他状态进行更新。例如,如果电梯门处于运行状态,则无法开门,如果电梯门处于停止状态,则可以开门。
类图如下:
代码如下:
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
(
)
;
//停止
}
}
问题分析:
- 。
。
1.2 结构
状态模式包含以下主要角色。
- 。
- 。
- 。
1.3 案例实现
对上述电梯的案例使用状态模式进行改进。类图如下:
代码如下:
//抽象状态类 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.4 优缺点
- ,只需要改变对象状态即可改变对象的行为。
- 。
- 。
- 。
- 。
1.5 使用场景
- 。
- 。
2. 观察者模式
2.1 概述
。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
2.2 结构
在观察者模式中有如下角色:
- 。
- 。
- 。
- 。
2.3 案例实现
【例】微信公众号
在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号。
类图如下:
代码如下:
定义抽象观察者类,里面定义一个更新的方法
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<Observer> weixinUserlist = new ArrayList<Observer>();
@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(