接前篇,行为型设计模式数量较多,之前没有讲完,还剩下备忘录模式、状态模式、策略模式和中介者模式,本章继续。
备忘录模式
备忘录模式用于保存对象的状态,当有需要时再恢复过来。例如对文档进行操作时操作错误,想要恢复到上一步正确的状态,那么就需要对上一次正确的操作状态进行保存。
通常应用于游戏状态保存,文档快照保存等。
具体设计到以下几个对象
-Originator:需要保存的对象。这个对象可能会很复杂或者内容繁多,如果每次都将它复制一份将会耗费大量内存,所以可以只保存它的状态即可。至于每种状态下对象应该如何管理和显示,则由originer自己来实现和负责。
-memo:备忘录对象。为什么要专门弄一个备忘录对象,因为状态可能有很多类型,所以一个基本类型不一定能囊括得了,比如斗地主的时候当前的游戏进度,玩家信息,手上牌的张数大小等等都不一样。备忘录对象由originer创建,它会保存几个originer的状态信息,当originer要恢复到以前的状态时就将自己的状态值传给originer.
-CareTaker:备忘录管理者。因备忘录对象不止一个,所以还需要一个管理者,它负责存储和清除备忘录。
代码如下:
Originator
public class Originator {
private String state;
private int step;
public void setState(String state,int step) {
this.state = state;
this.step = step;
}
public void setStep(int step) {
this.step = step;
}
public Memo saveMemo(){
return new Memo(state,step);
}
public void restoreFormMemo(Memo memo){
state = memo.getState();
step = memo.getStep();
}
public String getState() {
return state;
}
public int getStep() {
return step;
}
@Override
public String toString() {
return "Originator{" +
"state='" + state + '\'' +
", step=" + step +
'}';
}
}
Memo
public class Memo {
private String state;
private int step;
public Memo(String state, int step) {
this.state = state;
this.step = step;
}
public String getState() {
return state;
}
public int getStep() {
return step;
}
}
CareTaker
public class CareTaker {
private List<Memo> memoList = new ArrayList<>();
public void addMemo(Memo memo){
memoList.add(memo);
}
public void removeMemo(Memo memo){
memoList.remove(memo);
}
public Memo getMemo(int index){
return memoList.get(index);
}
}
测试代码
public static void main(String[] args) {
Originator originator = new Originator();
originator.setState("state 1...",1);
CareTaker taker = new CareTaker();
taker.addMemo(originator.saveMemo());
System.out.println("初始值:"+ originator);
originator.setState("state 2...",2);
originator.setState("state 3...",3);
System.out.println("改变之后:"+ originator);
taker.addMemo(originator.saveMemo());
originator.restoreFormMemo(taker.getMemo(0));
System.out.println("恢复到之前:"+ originator);
}
状态模式
该模式和策略模式类似,都是为了避免在项目中使用过多的条件判断,多层的条件判断会让代码易读性变差且难以维护。如果在不通的状态下需要进行不同的行为操作,则可以使用状态模式。
该模式会把行为抽象成一个接口,每个具体行为会根据这个接口传入的state不同来进行自己的操作。
主要包含以下类:
-context:环境类,它保存了当前的状态接口类,提供一个改变当前状态的方法,其工作直接由状态类实现。
-action:接口;每一个具体的执行者都实现了该接口。
-具体的执行类。
例如,小明昨天上班路上扶老奶奶过马路,老奶奶强行给了他一百块钱作为报酬,于是小明开开心心的去上班,昨天的工作效率很高,一会儿就把事情做完了;而今天上班路上遇到另一位老奶奶碰瓷,让他赔偿几万块的医药费,小明就一直在愤懑社会为什么这么多坏人所以无心工作,今天上班啥也没干成。这就是在不同的状态下工作结果不一样。
具体代码如下:
State
public interface State {
void doWork();
}
WorkHappy
public class WorkHappy implements State {
@Override
public void doWork() {
System.out.println("WorkHappy ...");
}
}
WorkSad
public class WorkSad implements State {
@Override
public void doWork() {
System.out.println("WorkSad ...");
}
}
Context
public class Context {
private State state;
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void changeState(State state){
this.state = state;
}
public void doWork(){
state.doWork();
}
}
测试代码
public static void main(String[] args) {
Context context = new Context();
context.setState(new WorkHappy());
context.doWork();
context.changeState(new WorkSad());
context.doWork();
}
策略模式
本模式和状态模式很相似,都是在面临复杂业务逻辑的时候为了避免陷入多种条件判断的地狱而产生的设计模式,不同的是,策略模式是对同一事情的不同策略实现,不注重时间策略切换,状态模式是在不同状态下做不同的事情,侧重状态的切换变化。
具体类如下:
-strategy:策略接口。对一件事情做法的抽象,可以有多个实现方法
-context:环境类。持有策略接口的引用,使用了某个策略的类。
例如:加减乘除分别代表了不同的算法,现在有两个数字a,b,假设对他们进行这四种运算都算是实现某种结果的四种策略,那么可以定义一个运算接口,然后分别实现四种策略算法。
代码如下:
Strategy
public interface Strategy {
int operation(Num num);
}
Num
public class Num {
private int a;
private int b;
public Num(int a, int b) {
this.a = a;
this.b = b;
}
public int getA() {
return a;
}
public int getB() {
return b;
}
}
StrategyAdd
public class StrategyAdd implements Strategy {
@Override
public int operation(Num num) {
return num.getA() + num.getB();
}
}
Context
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(Num num){
return strategy.operation(num);
}
}
其他集中算法实现就不贴了,一看了然。直接看测试代码:
public static void main(String[] args) {
Num num = new Num(300,20);
Context addContext = new Context(new StrategyAdd());
System.out.println("add num ="+addContext.executeStrategy(num));
Context subContext = new Context(new StrategySub());
System.out.println("sub num ="+subContext.executeStrategy(num));
Context multiContext = new Context(new StrategyMulti());
System.out.println("multi num ="+multiContext.executeStrategy(num));
Context divContext = new Context(new StrategyDiv());
System.out.println("div num ="+divContext.executeStrategy(num));
}
中介者模式
当对象与对象之间的关系错综复杂时,容易造成管理混乱和出错,因此提供中介者。它会将各个不同的对象进行协调和调配,使之协同工作。
有了中介者之后,对象不在与各自对象进行沟通交互,而直接和中介者进行沟通,这样原来的网状关系结构变成了中心点放射式结构。
例如房屋中介将所有房源都收集起来,租户需要租房时直接找中介者就能避免很多琐碎的程序和风险问题,让专业的人做专业的事,恰好符合单一职责原则。
再比如用户和用户聊天需要聊天室,聊天室就类似于一个中介者,它会将每个用户的消息,姓名,发送时间展示给其他用户看。
代码如下:
User
public interface User {
String getName();
void sendMsg(String msg);
}
XiaoHong
public class XiaoHong implements User{
@Override
public String getName() {
return "XiaoHong";
}
@Override
public void sendMsg(String msg) {
ChatRoom.sendMsg(this,msg);
}
}
Xiaoming
public class Xiaoming implements User{
@Override
public String getName() {
return "Xiaoming";
}
@Override
public void sendMsg(String msg) {
ChatRoom.sendMsg(this,msg);
}
}
ChatRoom
public class ChatRoom {
public static void sendMsg(User user,String msg){
System.out.println(user.getName()+" say "+msg);
}
}
测试代码
public static void main(String[] args) {
User xiaoMing = new XiaoHong();
xiaoMing.sendMsg("how ary you?");
User xiaoHong = new Xiaoming();
xiaoHong.sendMsg("fine,think you.");
}