原创

JAVA设计模式(十一)

温馨提示:
本文最后更新于 2022年10月27日,已超过 918 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

十九-中介者模式

在工作和生活中,常常会出现多个对象之间存在复杂的关系,这种关系是网状结构,即一个对象必须记住它需要交互的对象,当其中一个对象状态发生变化时,将会影响到和它有关联的所有对象。如房东和租客之间的关系(1对多),当房东的电话号码发生改变时,需要一个一个的通知到租客,这样就比较复杂。如果房东和租客之间有一个房屋中介,这样就把房东和租客的关系调整为了1对1,大大降低了房东和租客之间的耦合性,这种为星形结构

1.中介者模式的定义与特点

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

2. 优点

  • 降低了对象之间的耦合性,使得对象易于独立地被复用。
  • 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。

3. 缺点:

  • 中介对象的复杂程度由同事类来决定,当同事类过多时,中介者对象将会变得庞大且复杂

2. 模式的结构和实现

中介者包含四个基本的角色,抽象中介者角色具体中介者角色抽象同事类具体同事类

1. 模式的结构

  • 抽象中介者角色: 定义一个接口,包含一个注册同事类的方法和转发方法
  • 具体中介者角色: 实现抽象中介者接口,包含一个管理同事类的集合,通过转发方法来协调各个同事类之间的交互关系。
  • 抽象同事类角色:定义一个同事类接口,保存一个中介者对象,提供同事对象交互的抽象方法。
  • 具体同事类角色:实现抽象同事类接口,当需要与其他同事对象进行交互时,通过中介者对象负责后续交互。
  • 结构图:

image-20221017164914599

2.模式的实现

//抽象中介者角色
public interface AbstractMediator {
    //注册抽象同事角色
    void register(AbstractColleague colleague);
    //转发消息
    void relay(AbstractColleague colleague);
}

//抽象同事类角色
public abstract class AbstractColleague {
    //包含中介者对象
    protected AbstractMediator mediator;
    //设置中介者对象方法
    public void setMediator(AbstractMediator mediator){
        this.mediator = mediator;
    }
    //接收消息方法
    public abstract void receive();
    //发送消息方法
    public abstract void send();

}

//具体中介者角色
public class SpecificMediator implements AbstractMediator {

    //包含一个管理所有同事对象的集合
    private List<AbstractColleague> colleagueList = new ArrayList<>();

    //注册同事对象
    @Override
    public void register(AbstractColleague colleague) {
        if (!colleagueList.contains(colleague)) {
            colleague.setMediator(this);
            colleagueList.add(colleague);
        }
    }

    //转发消息
    @Override
    public void relay(AbstractColleague colleague) {
        if (!CollectionUtils.isEmpty(colleagueList)){
            colleagueList.forEach(c -> {
                if (colleague!=c){
                    c.receive();
                }
            });
        }
    }
}

//具体同事类角色1
public class SpecificColleagueOne extends AbstractColleague{

    @Override
    public void receive() {
        System.out.println("同事类角色1111收到消息");
    }

    @Override
    public void send() {
        System.out.println("同事类角色1111发出消息");
        mediator.relay(this);
    }
}

//具体同事类角色2
public class SpecificColleagueTwo extends AbstractColleague {

    @Override
    public void receive() {
        System.out.println("同事类角色2222收到消息");
    }

    @Override
    public void send() {
        System.out.println("同事类角色2222发出消息");
        mediator.relay(this);
    }
}

//测试
    @Test
    public void mediator(){
        AbstractMediator mediator = new SpecificMediator();
        SpecificColleagueOne specificColleagueOne = new SpecificColleagueOne();
        SpecificColleagueTwo specificColleagueTwo = new SpecificColleagueTwo();
        mediator.register(specificColleagueOne);
        mediator.register(specificColleagueTwo);
        specificColleagueOne.send();
        System.out.println("-------------------");
        specificColleagueTwo.send();
    }

同事类角色1111发出消息
同事类角色2222收到消息
-------------------
同事类角色2222发出消息
同事类角色1111收到消息

3.模式的应用实例

QQ聊天(仅仅用于简单示例)。聊天为抽象中介者,张三李四的聊天为具体中介者,同事对象为张三,李四,模拟聊天。

//抽象中介者角色==聊天
public interface TalkAbstractMediator {

   //添加用户
   void addUser(UserAbstractColleague userAbstractColleague);

   void relay(UserAbstractColleague userAbstractColleague);

}

//具体中介者角色==张三 李四的聊天
public class SpecificTalkAbstractMediator implements TalkAbstractMediator{

    private List<UserAbstractColleague> userAbstractColleagueList = new ArrayList<>();

    @Override
    public void addUser(UserAbstractColleague userAbstractColleague) {
        if (!userAbstractColleagueList.contains(userAbstractColleague)){
            userAbstractColleague.setMediator(this);
            userAbstractColleagueList.add(userAbstractColleague);
        }
    }

    @Override
    public void relay(UserAbstractColleague userAbstractColleague) {
        if (!CollectionUtils.isEmpty(userAbstractColleagueList)){
            userAbstractColleagueList.forEach(u->{
                if (u!=userAbstractColleague){
                    u.receive(userAbstractColleague.userName+"说:"+userAbstractColleague.content);
                }
            });
        }
    }
}

//抽象同事类角色==用户
public abstract class UserAbstractColleague {
    //包含中介者对象==qq聊天
    protected TalkAbstractMediator mediator;
    //设置中介者对象方法==加好友
    public void setMediator(TalkAbstractMediator mediator){
        this.mediator = mediator;
    }

    protected String userName;
    protected String content;

    //接收消息
    public abstract void receive(String message);
    //发送消息
    public abstract void send(String content);

}

//具体同事类角色==用户
public class SpecificUserAbstractColleague extends UserAbstractColleague{

    public SpecificUserAbstractColleague(String userName){
        super.userName = userName;
    }

    @Override
    public void receive(String message) {
        System.out.println(message);
    }

    @Override
    public void send(String content) {
        this.content = content;
        mediator.relay(this);
    }
}
//测试
    @Test
    public void mediator(){
        TalkAbstractMediator talk = new SpecificTalkAbstractMediator();
        SpecificUserAbstractColleague zhangsan = new SpecificUserAbstractColleague("张三");
        SpecificUserAbstractColleague lisi = new SpecificUserAbstractColleague("李四");
        talk.addUser(zhangsan);
        talk.addUser(lisi);
        zhangsan.send("小四,好久不见了。");
        lisi.send("三哥好,晚上有空喝一杯?");
        zhangsan.send("可以,大概几点?");
        lisi.send("晚上7点半,老地方烧烤等你!!");
        zhangsan.send("好的,不见不散!");
        lisi.send("不见不散");
    }

张三说:小四,好久不见了。
李四说:三哥好,晚上有空喝一杯?
张三说:可以,大概几点?
李四说:晚上7点半,老地方烧烤等你!!
张三说:好的,不见不散!
李四说:不见不散

3.模式的应用场景

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

4.中介者模式的扩展

实际开发中,通过以下两种方式简化中介者模式

  • 不定义中介者接口,把具体中介者对象实现成为单例。
  • 同事对象不持有中介者,而是在需要的时直接获取中介者对象并调用。

上述实例代码简化

//具体中介者角色==张三 李四的聊天==单例
public class SpecificMediatorSingleton{

    private SpecificMediatorSingleton(){}

    public static SpecificMediatorSingleton getInstance(){
        return specificMediatorSingletonEnum.INSTANCE.getSingleton();
    }

    private List<UserAbstractColleagueSingleton> userAbstractColleagueList = new ArrayList<>();

    public void addUser(UserAbstractColleagueSingleton userAbstractColleague) {
        if (!userAbstractColleagueList.contains(userAbstractColleague)){
            userAbstractColleagueList.add(userAbstractColleague);
        }
    }

    public void relay(UserAbstractColleagueSingleton userAbstractColleague) {
        if (!CollectionUtils.isEmpty(userAbstractColleagueList)){
            userAbstractColleagueList.forEach(u->{
                if (u!=userAbstractColleague){
                    u.receive(userAbstractColleague.userName+"说:"+userAbstractColleague.content);
                }
            });
        }
    }

    enum specificMediatorSingletonEnum{
        INSTANCE;
        private SpecificMediatorSingleton singleton;
        public SpecificMediatorSingleton getSingleton(){
            if (null==singleton){
                singleton = new SpecificMediatorSingleton();
            }
            return singleton;
        }
    }

}

//抽象同事类角色==用户
public abstract class UserAbstractColleagueSingleton {
    protected String userName;
    protected String content;

    //接收消息
    public abstract void receive(String message);
    //发送消息
    public abstract void send(String content);

}

//具体同事类角色==用户
public class SpecificUserAbstractColleagueSingleton extends UserAbstractColleagueSingleton {

    public SpecificUserAbstractColleagueSingleton(String userName){
        super.userName = userName;
    }

    @Override
    public void receive(String message) {
        System.out.println(message);
    }

    @Override
    public void send(String content) {
        this.content = content;
        SpecificMediatorSingleton.getInstance().relay(this);
    }
}

//测试
    @Test
    public void mediator(){
        SpecificMediatorSingleton talk = SpecificMediatorSingleton.getInstance();
        UserAbstractColleagueSingleton zhangsan = new SpecificUserAbstractColleagueSingleton("张三");
        UserAbstractColleagueSingleton lisi = new SpecificUserAbstractColleagueSingleton("李四");
        talk.addUser(zhangsan);
        talk.addUser(lisi);
        zhangsan.send("小四,好久不见了。");
        lisi.send("三哥好,晚上有空喝一杯?");
        zhangsan.send("可以,大概几点?");
        lisi.send("晚上7点半,老地方烧烤等你!!");
        zhangsan.send("好的,不见不散!");
        lisi.send("不见不散");
    }

二十-迭代器模式

在现实生活以及程序设计中,经常要访问一个聚合对象中的各个元素,如“数据结构"中的链表遍历,通常的做法是将链表的创建和遍历都放在同一个类中,但这种方式不利于程序的扩展,如果要更换遍历方法就必须修改程序源代码,这违背了“开闭原则”。

“迭代器模式”在客户访问类与聚合类之间插入一个迭代器,这分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,且满足“单一职责原则”和“开闭原则”,如Java中的Collection、List、Set、Map等都包含了迭代器。

1.模式的定义与特点

迭代器模式:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式是一种对象行为型模式。

优点:

  • 访问一个聚合对象的内容而无须暴露它的内部表示。
  • 遍历任务交由迭代器完成,这简化了聚合类。
  • 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
  • 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
  • 封装性良好,为遍历不同的聚合结构提供一个统一的接口。

缺点:

  • 增加系统的复杂度

2.模式的结构和实现

迭代器模式包含抽象聚合角色具体聚合角色抽象迭代器角色具体迭代器角色

1.迭代器模式的结构

  • 抽象聚合角色: 定义一个抽象接口,包含添加,移除聚合对象的方法,包含获取迭代器对象的方法。
  • 具体聚合角色: 实现抽象聚合接口,具体方法的实现者,包含一个存储对象的集合。
  • 抽象迭代器角色: 定义访问和遍历聚合对象的接口,通常包含 hasNext(),next()等等方法(参考java util中的iterator)
  • 具体迭代器角色:实现抽象迭代器接口,实现访问和遍历方法,记录当前遍历位置

image-20221017195812613

2.迭代器模式的实现实例

以人民币汇率对进出口公司的影响为例。人民币汇率升值时,进口公司的进口成本和利润率会变高,出口公司的出口成本变高和利润率变低。反之,同理

//抽象聚合
public abstract class AbstractAggregate {

    public abstract void addObject(Object o);

    public abstract void removeObject(Object o);

    public abstract AbstractIterator getIterator();

}

//具体聚合
public class SpecificAggregate extends AbstractAggregate{

    private List<Object> objectList = new ArrayList<>();

    @Override
    public void addObject(Object o) {
        objectList.add(o);
    }

    @Override
    public void removeObject(Object o) {
        objectList.remove(o);
    }

    @Override
    public AbstractIterator getIterator() {
        return new SpecificIterator(objectList);
    }
}

//抽象迭代器
public abstract class AbstractIterator {

    public abstract boolean hasNext();

    public abstract Object getFirst();

    public abstract Object next();
}

//具体迭代器
public class SpecificIterator extends AbstractIterator{

    private List<Object> objectList;
    private int index = -1;
    public SpecificIterator(List<Object> objectList){
        this.objectList = objectList;
    }
    @Override
    public boolean hasNext() {
        if (index<objectList.size()-1){
            return true;
        }
        return false;
    }
    @Override
    public Object getFirst() {
        if (CollectionUtils.isEmpty(objectList)){
            return null;
        }
        return objectList.get(0);
    }
    @Override
    public Object next() {
        return objectList.get(++index);
    }
}

//测试
    @Test
    public void iterator(){
        AbstractAggregate aggregate = new SpecificAggregate();
        aggregate.addObject("张三");
        aggregate.addObject("李四");
        aggregate.addObject("王五");
        aggregate.addObject("赵六");
        AbstractIterator iterator = aggregate.getIterator();
        while (iterator.hasNext()){
            Object next = iterator.next();
            System.out.println(next.toString()+"\t");
        }
        System.out.println("首个元素:"+iterator.getFirst().toString());
    }

张三    
李四    
王五    
赵六    
首个元素:张三

3. 迭代器模式的应用场景

  • 当需要为聚合对象提供多种遍历方式时。
  • 当需要为遍历不同的聚合结构提供一个统一的接口时。
  • 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。

由于聚合与迭代器的关系非常密切,所以大多数语言在实现聚合类时都提供了迭代器类,因此大数情况下使用语言中已有的聚合类的迭代器就已经够了。

正文到此结束