设计模式——外观模式和备忘录模式

设计模式之外观模式和备忘录模式

外观模式

  1. 概述
      外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性
      为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度
      例子:一个电源总开关可以控制四盏灯、一个风扇、一台空调和一台电视机的启动和关闭。该电源总开关可以同时控制上述所有电器设备,电源总开关即为该系统的外观模式设计。
    这里写图片描述

  2. 类图
    这里写图片描述

  3. 外观模式与适配器的差异
      外观模式:提供简化的接口,也将客户从组件的子系统中解耦,仍然可以直接调用子系统中的接口,其主要是提供一个整洁的一致的接口给客户端
      适配器:增加适配接口,将一个接口通过适配来间接转换为另一个接口,以符合客户的期望
      外观和适配器可以“包装”许多类,差异不在于它们包装了几个类,而在于它们的意图:适配器的意图是改变接口符合客户的期望,外观模式的意图是提供子系统的一个简化接口

  4. 实例

/**
 * 子系统类
 *
 */
class familyAppliances {
    private String state = "off";

    public String getState() {
        return state;
    }

    public void turnOn() {
        this.state = "turn on";
    }

    public void turnOff() {
        this.state = "turn off";
    }
}
// 电灯
class Light extends familyAppliances {
}
// 电扇
class Fan extends familyAppliances {
}
// 空调
class AirConditioner extends familyAppliances {
}
// 电视
class Television extends familyAppliances {
}
/**
 * 外观类
 *
 */
 class SwitchFacade {
     Light light = new Light();
     Fan fan = new Fan();
     AirConditioner ac = new AirConditioner();
     Television tv = new Television();
// 晚上需要对灯(light)进行操作
     public void night(String button) {
         if (button == "ON") {
             this.light.turnOn();
             this.fan.turnOn();
             this.ac.turnOn();
             this.tv.turnOn();
         } else {
            this.light.turnOff();
            this.fan.turnOff();
            this.ac.turnOff();
            this.tv.turnOff();
         }
     }
// 白天不需要对灯(light)进行操作
     public void day(String button) {
         if (button == "ON") {
             this.fan.turnOn();
             this.ac.turnOn();
             this.tv.turnOn();
         } else {
             this.fan.turnOff();
             this.ac.turnOff();
             this.tv.turnOff();
         }
     }
// 打印当前家电的状态
     public void printState() {
         System.out.println("light state:" + this.light.getState());
         System.out.println("fan state:" + this.fan.getState());
         System.out.println("ac state:" + this.ac.getState());
         System.out.println("tv state:" + this.tv.getState());
         System.out.println("operation success! \n");
     }
 }
/**
 * 客户类
 *
 */
 public class clientFacade {
    public static void main(String[] args) {
        SwitchFacade facade = new SwitchFacade();
        System.out.println("initialize...");
        facade.printState();

        facade.day("ON");
        System.out.println("day ON...");
        facade.printState();

        facade.night("OFF");
        System.out.println("night OFF...");
        facade.printState();
    }
}

Run result:
这里写图片描述

  1. 优缺点
    Facade模式有下面一些优点

    • 对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。
    • 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。
    • 降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
    • 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
    • 最少知识原则:只和你的密友谈话

    Facade模式的缺点

    • 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。
    • 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。

备忘录模式

  1. 概述
    在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态

  2. 设计角色

    • Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。

    • Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。
      备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。

    • Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。
  3. 类图
    这里写图片描述

  4. 实例

//发起人
class Originator {
    private String state = "";

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public Memento createMemento() {
        return new Memento(this.state);
    }

    public void restoreMemento(Memento memento) {
        this.setState(memento.getState());
    }
}
//备忘录
class Memento {
    private String state = "";

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}
//管理者
class Caretaker {
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}
//客户类
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        originator.setState("state one");    //初始化发起人状态
        System.out.println("first state:" + originator.getState());

        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMemento());  //将发起人的当前状态存储到备忘录中
        originator.setState("state two");    //设置第二种状态
        System.out.println("changed state:" + originator.getState());

        originator.restoreMemento(caretaker.getMemento());     //将发起人状态恢复成备忘录中的状态
        System.out.println("restored state:" + originator.getState());
    }
}

Run result:
这里写图片描述

  1. Memento优缺点
    备忘录模式的优点:

    • 当发起人角色中的状态改变时,有可能是个错误的改变,我们使用备忘录模式就可以把这个错误的改变还原。
    • 备份的状态是保存在发起人角色之外,这样发起人角色就不需要对各个备份的状态进行管理

    备忘录模式的缺点:

    • 在实际应用中,备忘录模式都是多状态和多备份的,发起人角色的状态需要存储到备忘录对象中,对资源的消耗比较严重。
  2. 适用场景
    如果有需要提供回滚操作的需求,使用备忘录模式非常适合,比如文本编辑器的Ctrl+Z操作等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值