美文网首页
[Common] Head First 设计模式 (状态 + 代

[Common] Head First 设计模式 (状态 + 代

作者: 木小易Ying | 来源:发表于2020-04-16 22:56 被阅读0次

Chapter 10 状态模式

假设需要这样一个自动糖果机:


糖果机 提取状态

就投入25分硬币的部分可以这样写:

public void insertQuarter(){
  if(state==HAS_QUARTER){
  // 已经投过了
  }else if(state==SOLD_OUT){
  // 售罄
  }else if(state ==SOLD){
  // 已经制作完给过顾客了,这个状态其实是中间态,然后会自动转换到NO_QUARTER
  }else if(state==NO_QUARTER){
  // 投入了25分正好,进入下个流程
  }
}

看起来好像我们很好的处理了需求,但是如果用户增加需求说有10%的概率可以拿到一枚免费糖果,你可能就要增加一种状态,并在每个操作函数里面处理这种状态,非常不符合封装变化的需求。

不要维护我们现有的代码,我们重写它以便于将状态对象封装在各自的类中,然后在动作发生时委托给当前状态。

  1. 首先,我们定义一个State接口,在这个接口内,糖果机的每个动作都有一个对应的方法。
  2. 然后为机器中的每个状态实现状态类,这些类将负责在对应的状态下进行机器的行为。
  3. 最后,我们要摆脱旧的条件代码,取而代之的方法是,将动作委托到状态类。

现在我们要把一个状态的所有行为放在一个类中,这么一来我们将行为局部化了,并使得事情更容易改变和理解。

interface State{
  void insertQuarter();
  void ejectQuarter();
  void turnCrank();
  void dispense();
}

用state处理操作可以去掉 if else 判断的模式~

class NoQuarterState implements State{

    GumballMachine gumballMachine;
    public NoQuarterState(GumballMachine gumballMachine){
        this.gumballMachine=gumballMachine;
    }

    @Override
    public void insertQuarter() {
        System.out.println("如果有人投入了25分钱,我们就打印出一条消息,说我们接受了25分钱," +
                "然后改变机器的状态到HasQuarterState");
        gumballMachine.setState(gumballMachine.getHasQuarterState());
    }

    @Override
    public void ejectQuarter() {
        System.out.println("如果没给钱,就不要求退钱");
    }

    @Override
    public void turnCrank() {
        System.out.println("如果没给钱,就不能要求糖果");
    }

    @Override
    public void dispense() {
        System.out.println("如果没得到钱,我们就不能发放糖果。");
    }
}

=====

class GumballMachine_ {
    State soldOutState;
    State noQuarterState;
    State hasQuarterState;
    State soldState;

    State state = soldState;
    int count = 0;

    public GumballMachine_(int count) {
        soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldOutState = new SoldState(this);
        this.count = count;
        if (count > 0) {
            state = noQuarterState;
        }
    }
    public void insertQuarter() {
        state.insertQuarter();
    }

    public void ejectQuarter() {
        state.ejectQuarter();
    }

    public void turnCrank(){
        state.turnCrank();
        state.dispense();
    }
    void setState(State state){
        this.state=state;
    }
    void releaseBall(){
        System.out.println();
        if(count!=0){
            count=count-1;
        }
    }
    public State getSoldState() {
        return soldState;
    }

    public State getHasQuarterState() {
        return hasQuarterState;
    }

    public State getNoQuarterState() {
        return noQuarterState;
    }

    public State getSoldOutState() {
        return soldOutState;
    }
}

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

state是可以被多个context共享的哈如果需要的话~

状态类图

状态模式和策略模式的类图是一样的,但是策略模式其实不会改变持有的策略,一般都是在运行时固定一种;而状态模式相反,状态是不固定的,需要流转

  • 这里为什么需要吧winnder(2颗糖) 和sold状态区分开作为两个类呢,明明内容都是类似的?
    => 因为一个类应该只有一种责任,以及如果商家要取消2颗糖这个策略的时候,分开的类你很好维护,状态很清晰,如果都放入sold,有多少种促销策略你的sold state就会有多复杂,任意一个有了变化你要考虑的修改就需要很谨慎。

策略模式:将可以互换的行为封装起来,然后使用委托决定使用哪一种行为
模板方法:由子类决定如何实现算法中的某些步骤
状态模式:封装基于状态的行为,并将行为委托给当前状态


Chapter 11 代理模式

假设要给糖果机加个监控,需要放在老板电脑上面运行,而糖果机的代码不在老板的电脑上,这要怎么将糖果机的实例对象传给监控呢?

这就需要远程调用了,也就是糖果机提供一个虚拟的接口给监控,然后监控调用这个虚拟糖果机,远程电脑上的实际糖果机就会运行。

远程代理就是远程对象的本地代表

远程糖果机

这里其实就是客户调用了代理的方法,代理通过网络将方法调用传给实际对象,实际对象执行后再将结果通过网络返回给代理。

代理模式:为另一个对象提供一个替身或占位符控制这个对象的访问

类图
  • 特点:
    让代理对象控制对象的访问,被代理对象可以是远程对象(远程代理),创建开销较大对象(虚拟代理),或需要安全控制的对象(保护代理)
    为另一个对象提供代表,以便控制客户对对象的访问

=> 远程代理:好比远程对象(在不同JVM虚拟机的对象)的本地代表(本地方法的行为转移到远程),帮助我们处理网络上的细节

=> 虚拟代理:作为创建开销大的对象的代表
在大对象创建前和创建中由虚拟对象代替大对象,在创建完毕后将动作委派给大对象

=> 保护代理:通过代理实现不同的用户对对象有不同的访问权限
=> 动态代理:通过反射在运行过程中动态的创建代理,根据传入的接口集创建。Java内置动态代理支持
=> 防火墙代理:控制网络资源的访问,保护主题免于坏客户的侵害
=> 智能引用代理:当主题被引用时,进行额外的动作,例如记录独享被引用的次数
=> 缓存代理:为开销大的运算结果提供暂时存储;允许多个客户共享结果,减少计算或网络延迟
=> 同步代理:多线程下为主题提供安全访问
=> 复杂隐藏代理:用来隐藏一个类的复杂集合的复杂度
=> 写入时复制代理:用来控制对象的复制,延迟对象的复制,知道客户真的需要

🌰 这里举一个“虚拟代理”的例子,例如加载大图片的时候,需要很长时间加载,如果加载很久界面就会空白,所以可以创建一个图片加载的代理,当调用的时候先显示loading,同时异步加载图片真的返回以后再展示图片。

  • 代理和装饰者的区别:代理是控制访问,而装饰者是为了增加功能,虽然两者都是把对象包起来。
  • 代理和适配器的区别:代理提供相同接口,适配器提供不同接口

如果想让客户使用代理而非真正对象,可以结合工厂模式,这样只对外提供代理即可。


Chapter 12 复合模式

复合模式:结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题。如MVC

MVC

这里其实控制器可以理解为模型的observer,当模型内不发生变化,控制器可以收到通知来改变view例如disable某个按钮。

控制器的职责之一是接受view的输入,将用户输入设置到model上面,但是它的职责不仅仅是这样。即使controller只是这个责任,如果把改变model的职责给view,view和model就强耦合了,在其他场景如果想用view就不行了。

模式 策略模式 举例

MVC中model对VC一无所知哦,他只是通知观察者,是完全解耦的。当然他是提供设置状态的接口的,让VC改变它。


Chapter 13 真实世界中的模式

  • 模式是在某情境(context)下,针对某问题的某种解决方案。
    情境:就是应用某个模式的情况。这应该是会不断出现的情况。
    问题:就是你想在某情境下达到的目标,但也可以是某情境下的约束。
    解决方案:就是你所追求的:一个通用的设计,用来解决约束、达到目标。

注意哦,模式要应用于重复出现的问题哈~

分类

附录

可以参考https://www.jianshu.com/p/9079dd0013d8 或者 https://blog.csdn.net/roymuste/article/details/8539082

相关文章

网友评论

      本文标题:[Common] Head First 设计模式 (状态 + 代

      本文链接:https://www.haomeiwen.com/subject/smrlmhtx.html