设计模式回顾(四)

接前篇,行为型设计模式数量较多,之前没有讲完,还剩下备忘录模式、状态模式、策略模式和中介者模式,本章继续。

备忘录模式

备忘录模式用于保存对象的状态,当有需要时再恢复过来。例如对文档进行操作时操作错误,想要恢复到上一步正确的状态,那么就需要对上一次正确的操作状态进行保存。
通常应用于游戏状态保存,文档快照保存等。
具体设计到以下几个对象
-Originator:需要保存的对象。这个对象可能会很复杂或者内容繁多,如果每次都将它复制一份将会耗费大量内存,所以可以只保存它的状态即可。至于每种状态下对象应该如何管理和显示,则由originer自己来实现和负责。
-memo:备忘录对象。为什么要专门弄一个备忘录对象,因为状态可能有很多类型,所以一个基本类型不一定能囊括得了,比如斗地主的时候当前的游戏进度,玩家信息,手上牌的张数大小等等都不一样。备忘录对象由originer创建,它会保存几个originer的状态信息,当originer要恢复到以前的状态时就将自己的状态值传给originer.
-CareTaker:备忘录管理者。因备忘录对象不止一个,所以还需要一个管理者,它负责存储和清除备忘录。


image.png

代码如下:
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:接口;每一个具体的执行者都实现了该接口。
-具体的执行类。
例如,小明昨天上班路上扶老奶奶过马路,老奶奶强行给了他一百块钱作为报酬,于是小明开开心心的去上班,昨天的工作效率很高,一会儿就把事情做完了;而今天上班路上遇到另一位老奶奶碰瓷,让他赔偿几万块的医药费,小明就一直在愤懑社会为什么这么多坏人所以无心工作,今天上班啥也没干成。这就是在不同的状态下工作结果不一样。


image.png

具体代码如下:
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,假设对他们进行这四种运算都算是实现某种结果的四种策略,那么可以定义一个运算接口,然后分别实现四种策略算法。


image.png

代码如下:
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));
    }

中介者模式

当对象与对象之间的关系错综复杂时,容易造成管理混乱和出错,因此提供中介者。它会将各个不同的对象进行协调和调配,使之协同工作。
有了中介者之后,对象不在与各自对象进行沟通交互,而直接和中介者进行沟通,这样原来的网状关系结构变成了中心点放射式结构。
例如房屋中介将所有房源都收集起来,租户需要租房时直接找中介者就能避免很多琐碎的程序和风险问题,让专业的人做专业的事,恰好符合单一职责原则。
再比如用户和用户聊天需要聊天室,聊天室就类似于一个中介者,它会将每个用户的消息,姓名,发送时间展示给其他用户看。


image.png

代码如下:
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.");
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容