设计模式:(六)迭代器、观察者、中介者、备忘录模式

一、迭代器模式

1、概述

1、迭代器(Iterator)模式:提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素, 不需要知道集合对象的底层表示(即:不暴露其内部的结构)。迭代器模式是一种对象行为型模式。

2、主要角色

1、抽象迭代器(Iterator):定义访问和遍历聚合元素的接口,通常包含hasNext()、next()、remove()等方法。
2、具体迭代器(Concretelterator):实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
3、抽象聚合(Aggregate):定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
4、具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

3、迭代器模式实现

/**
 * 具体迭代器
 */
public class InfoColleageIterator implements Iterator {
    /**
     * 以list方式存放数据
     */
    List<Department> list;

    public InfoColleageIterator(List<Department> list) {
        this.list = list;
    }

    //索引位置
    int index = -1;

    /**
     * 判断集合中是否有下一个元素
     * @return
     */
    @Override
    public boolean hasNext() {
        if (index >= list.size() - 1) {
            return false;
        } else {
            index += 1;
            return true;
        }
    }

    /**
     * 获取数据
     * @return
     */
    @Override
    public Object next() {
        return list.get(index);
    }
}

/**
 * 具体迭代器
 */
public class ComputerCollegeIterator implements Iterator {
    /**
     * 以数组方式存放数据
     */
    Department[] departments;

    public ComputerCollegeIterator(Department[] departments) {
        this.departments = departments;
    }

    //遍历位置
    int position = 0;

    /**
     * 判断是否有下一个元素
     * @return
     */
    @Override
    public boolean hasNext() {
        if (position >= departments.length || departments[position] == null) {
            return false;
        }
        return true;
    }

    /**
     * 取出数据
     * @return
     */
    @Override
    public Object next() {
        Department department = departments[position];
        position += 1;
        return department;
    }
}

/**
 * 系别属性
 */
@Data
@AllArgsConstructor
public class Department {
    private String name;

    private String desc;
}
/**
 * 抽象聚合
 */
public interface ColleageAggregate {
    public String getName();

    /**
     * 增加系的方法
     * @param name
     * @param desc
     */
    public void add(String name,String desc);

    /**
     * 返回迭代器
     * @return
     */
    public Iterator createIterator();
}
/**
 * 具体聚合
 */
public class InfoAggregate implements ColleageAggregate {
    List<Department> departments;

    public InfoAggregate() {
        departments = new ArrayList<>();
        add("信息安全","保障信息安全");
        add("数据库安全","保障数据库安全");
        add("服务器安全","保障服务器安全");
    }

    @Override
    public String getName() {
        return "信息工程学院";
    }

    @Override
    public void add(String name, String desc) {
        Department department = new Department(name, desc);
        departments.add(department);
    }

    @Override
    public Iterator createIterator() {
        return new InfoColleageIterator(departments);
    }
}

public class ComputerAggregate implements ColleageAggregate {
    Department[] departments;

    public ComputerAggregate() {
        departments = new Department[5];
        add("Java","后台服务");
        add("MySQL","提供数据");
        add("HTML + CSS","美化页面");
    }

    //保存当前数据的对象个数
    int num = 0;

    @Override
    public String getName() {
        return "计算机学院";
    }

    @Override
    public void add(String name, String desc) {
        Department department = new Department(name, desc);
        departments[num] = department;
        num += 1;
    }

    @Override
    public Iterator createIterator() {
        return new ComputerCollegeIterator(departments);
    }
}
/**
 * 测试
 */
public class Client {
    public static void main(String[] args) {
        List<ColleageAggregate> colleage = new ArrayList<>();
        ComputerAggregate colleageAggregate = new ComputerAggregate();
        InfoAggregate infoAggregate = new InfoAggregate();

        colleage.add(colleageAggregate);
        colleage.add(infoAggregate);
        //取出所有学院,
        Iterator<ColleageAggregate> iterator = colleage.iterator();
        while (iterator.hasNext()) {
            ColleageAggregate next = iterator.next();
            System.out.println("==========" + next.getName() + "==========");
            //获取系别迭代器
            Iterator iterator1 = next.createIterator();
            while (iterator1.hasNext()) {
                Department department = (Department) iterator1.next();
                System.out.println(department.getName());
            }
        }
    }
}

/**
 * 运行结果:
 * ==========计算机学院==========
 * Java
 * MySQL
 * HTML + CSS
 * ==========信息工程学院==========
 * 信息安全
 * 数据库安全
 * 服务器安全
 */

4、优缺点说明

1、优点:
  • 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
  • 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
  • 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
  • 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
  • 封装性良好,为遍历不同的聚合结构提供一个统一的接口。
2、缺点:
  • 增加了类的个数,这在一定程度上增加了系统的复杂性。

5、应用场景

1、当需要为聚合对象提供多种遍历方式时。
2、当需要为遍历不同的聚合结构提供一个统一的接口时。
3、当访问一个聚合对象的内容而无须暴露其内部细节的表示时。
4、总结:由于聚合与迭代器的关系非常密切,所以大多数语言在实现聚合类时都提供了迭代器类,因此大数情况下使用语言中已有的聚合类的迭代器就已经够了。

二、观察者模式

1、概述

1、观察者(Observer)模式:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式。

2、主要角色

1、抽象主题(Subject):也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
2、具体主题(Concrete Subject):也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
3、抽象观察者(Observer):它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
4、具体观察者(Concrete Observer):实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

3、观察者模式实现

/**
 * 抽象主题
 */
public interface Subject {
    /**
     * 增加观察者方法
     * @param observer
     */
    void addObserver(Observer observer);

    /**
     * 移除方法
     * @param observer
     */
    void removeObserver(Observer observer);

    /**
     * 通知方法
     */
    void notifyObserver();
}
/**
 * 具体主题
 * 含有观察者集合,使用ArrayList管理
 * 当有数据更新时,就主动调用ArrayList,通知所有的(接入方)就看到最新的信息
 */
@Getter
public class ConcreteSubject implements Subject {
    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;
    //观察者集合
    private ArrayList<Observer> observers;

    public ConcreteSubject() {
        observers = new ArrayList<Observer>();
    }

    /**
     * 当有数据更新时,就调用setData
     * @param temperature
     * @param pressure
     * @param humidity
     */
    public void setData(float temperature,float pressure,float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        //调用dataChange,将最新消息推送到接入方
        dataChange();
    }

    /**
     * 更新所有通知
     */
    public void dataChange(){
        notifyObserver();
    }

    /**
     * 添加一个观察者
     * @param observer
     */
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    /**
     * 移除一个观察者
     * @param observer
     */
    @Override
    public void removeObserver(Observer observer) {
        if (observers.contains(observer)) {
            observers.remove(observer);
        }
    }

    /**
     * 遍历所有的观察者,并通知
     */
    @Override
    public void notifyObserver() {
        for (int i = 0; i < observers.size(); i++) {
            observers.get(i).update(this.temperature,this.pressure,this.humidity);
        }
    }
}
/**
 * 抽象观察者
 */
public interface Observer {
    /**
     * 更新方法
     * @param temperature
     * @param pressure
     * @param humidity
     */
    void update(float temperature,float pressure,float humidity);
}
/**
 * 具体观察者
 */
public class ConcreteObserver implements Observer {
    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;

    /**
     * 更新方法
     * @param temperature
     * @param pressure
     * @param humidity
     */
    @Override
    public void  update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    /**
     * 显示结果
     */
    private void display() {
        System.out.println("温度:" + temperature);
        System.out.println("气压:" + pressure);
        System.out.println("湿度:" + humidity);
    }
}
/**
 * 测试
 */
public class Client {
    public static void main(String[] args) {
        //创建一个具体主题对象
        ConcreteSubject concreteSubject = new ConcreteSubject();
        //创建观察者对象
        ConcreteObserver concreteObserver = new ConcreteObserver();
        //添加到concreteSubject
        concreteSubject.addObserver(concreteObserver);
        System.out.println("通知各个观察者。查看信息");
        concreteSubject.setData(19f,100f,30f);
    }
}
/**
 * 运行结果:
 * 通知各个观察者。查看信息
 * 温度:19.0
 * 气压:100.0
 * 湿度:30.0
 */

4、优缺点说明

1、优点:
  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
  • 目标与观察者之间建立了一套触发机制。
2、缺点:
  • 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
  • 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

5、应用场景

1、在软件系统中,当系统一方行为依赖另一方行为的变动时,可使用观察者模式松耦合联动双方,使得一方的变动可以通知到感兴趣的另一方对象,从而让另一方对象对此做出响应。
  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  • 实现类似广播机制的功能,不需要知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。
  • 多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。

三、中介者模式

1、概述

1、中介者(Mediator)模式:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

2、主要角色

1、抽象中介者(Mediator):它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
2、具体中介者(Concrete Mediator):实现中介者接口,定义一个集合来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
3、抽象同事类(Colleague):定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
4、具体同事类(Concrete Colleague):是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。

3、中介者模式实现

/**
 * 抽象中介者
 */
public abstract class Mediator {
    public abstract void register(Colleague colleague);

    public abstract void relay(Colleague cl);
}
/**
 * 具体中介者
 */
public class ConcreteMediator extends Mediator {
    //存放所有同事对象
    private List<Colleague> colleagues = new ArrayList<Colleague>();

    @Override
    public void register(Colleague colleague) {
        if (!colleagues.contains(colleague)) {
            colleagues.add(colleague);
            colleague.setMedium(this);
        }
    }

    @Override
    public void relay(Colleague cl) {
        for (Colleague ob : colleagues) {
            if (!ob.equals(cl)) {
                ((Colleague) ob).receive();
            }
        }
    }
}
/**
 * 抽象同事类
 */
public abstract class Colleague {
    protected Mediator mediator;

    public void setMedium(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void receive();

    public abstract void send();
}
/**
 * 具体同事类1
 */
public class ConcreteColleague1 extends Colleague {

    @Override
    public void receive() {
        System.out.println("具体同事类1收到请求。");
    }
    @Override
    public void send() {
        System.out.println("具体同事类1发出请求。");
        //请中介者转发
        mediator.relay(this);
    }
}

/**
 * 具体同事类2
 */
public class ConcreteColleague2 extends Colleague {

    @Override
    public void receive() {
        System.out.println("具体同事类2收到请求。");
    }

    @Override
    public void send() {
        System.out.println("具体同事类2发出请求。");
        //请中介者转发
        mediator.relay(this);
    }
}
/**
 * 测试
 */
public class Client {
    public static void main(String[] args) {
        //创建中介者对象
        Mediator md = new ConcreteMediator();
        Colleague c1, c2;
        c1 = new ConcreteColleague1();
        c2 = new ConcreteColleague2();
        md.register(c1);
        md.register(c2);
        c1.send();
        System.out.println("=================");
        c2.send();
    }
}

/**
 * 运行结果:
 * 具体同事类1发出请求。
 * 具体同事类2收到请求。
 * =================
 * 具体同事类2发出请求。
 * 具体同事类1收到请求。
 */

4、优缺点说明

1、优点:
  • 类之间各司其职,符合迪米特法则。
  • 降低了对象之间的耦合性,使得对象易于独立地被复用。
  • 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
2、缺点:
  • 中介者模式将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。

5、应用场景

1、当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。
2、当想创建一个运行于多个类之间的对象,又不想生成新的子类时。si

四、备忘录模式

1、概述

1、备忘录(Memento)模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

2、主要角色

1、发起人(Originator):记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
2、备忘录(Memento):负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
3、管理者(Caretaker):对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

3、备忘录模式实现

/**
 * 发起人
 */
public class Originator {
    private String state;

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

    public String getState() {
        return state;
    }

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

    public void restoreMemento(Memento m) {
        this.setState(m.getState());
    }
}
/**
 * 备忘录
 */
@Data
@AllArgsConstructor
public class Memento {
    private String state;
}
/**
 * 管理者
 */
public class Caretaker {
    private Memento memento;

    public void setMemento(Memento m) {
        memento = m;
    }

    public Memento getMemento() {
        return memento;
    }
}
/**
 * 测试
 */
public class Client {
    public static void main(String[] args) {
        Originator or = new Originator();
        Caretaker cr = new Caretaker();
        or.setState("S0");
        System.out.println("初始状态:" + or.getState());
        //保存状态
        cr.setMemento(or.createMemento());
        or.setState("S1");
        System.out.println("新的状态:" + or.getState());
        //恢复状态
        or.restoreMemento(cr.getMemento());
        System.out.println("恢复状态:" + or.getState());
    }
}
/**
 * 运行结果:
 * 初始状态:S0
 * 新的状态:S1
 * 恢复状态:S0
 */

4、优缺点说明

1、优点:
  • 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
  • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
  • 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
2、缺点:
  • 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。

5、应用场景

1、需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。
2、需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,Eclipse 等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值